Skip to content

feat(auth): add Kimi and Xiaomi MiMo providers - #8368

Open
DragonnZhang wants to merge 95 commits into
QwenLM:mainfrom
DragonnZhang:dragon/add-kimi-xiaomi-auth
Open

feat(auth): add Kimi and Xiaomi MiMo providers#8368
DragonnZhang wants to merge 95 commits into
QwenLM:mainfrom
DragonnZhang:dragon/add-kimi-xiaomi-auth

Conversation

@DragonnZhang

Copy link
Copy Markdown
Collaborator

What this PR does

Adds first-class Kimi and Xiaomi MiMo presets to /authThird-party Providers. Kimi appears as one provider with Coding Plan, API Key (China), and API Key (International) access choices; Xiaomi MiMo appears as one provider with pay-as-you-go plus China, Singapore, and Europe Token Plan endpoints.

Carries endpoint-specific model metadata through the CLI, ACP, daemon/SDK, VS Code, Web Shell, and desktop setup flows so each selected endpoint receives the correct default models and environment key. The third-party provider registry is displayed alphabetically, and the /auth lists now paginate according to the available terminal height with visible scroll arrows.

Why it's needed

Kimi and Xiaomi MiMo previously required users to recreate supported endpoints through Custom Provider, which was repetitive and made subscription-specific endpoints difficult to discover. Kimi also uses different credentials and model catalogs for Coding Plan versus its regional APIs, so a single flat model list would install invalid choices for some endpoints.

The provider list also became taller than the dialog after these additions. Its previous logical limit was ten items, but every descriptive item consumes multiple terminal rows, so the outer height constraint clipped content without activating list pagination.

Reviewer Test Plan

How to verify

  1. Launch the repository CLI and open /authThird-party Providers. Verify the displayed provider labels are alphabetical, DeepSeek remains first, and / appear when the list exceeds the available height. Continue pressing Down and verify Kimi and Xiaomi MiMo become visible without clipping the footer.
  2. Open Kimi. Verify the access choices are Coding Plan, API Key (China), and API Key (International). Coding Plan should recommend k3-256k, k3, kimi-for-coding, and kimi-for-coding-highspeed; either API option should recommend kimi-k3, kimi-k2.7-code, kimi-k2.7-code-highspeed, and kimi-k2.6.
  3. Open Xiaomi MiMo API Key. Verify the endpoint choices are pay-as-you-go, Token Plan (China), Token Plan (Singapore), and Token Plan (Europe), followed by mimo-v2.5-pro and mimo-v2.5 model recommendations.
  4. Cancel each flow before entering real credentials. Optionally repeat endpoint selection through VS Code, Web Shell, or desktop and confirm endpoint-specific default models remain consistent.

Automated validation: 157 core provider tests passed; core build and typecheck passed; 413 focused CLI tests passed; 10 VS Code auth-handler tests passed; SDK and VS Code typechecks passed; changed files passed ESLint and Prettier.

Evidence (Before & After)

Before: Kimi and Xiaomi MiMo were absent from Third-party Providers and required Custom Provider setup. The descriptive provider list could exceed the constrained dialog height while still reporting that all logical items fit, leaving later providers and the footer clipped.

After: A 100×24 macOS terminal running npm run dev -- --screen-reader kept the footer visible and moved the two-item viewport as Down was pressed:

Third-party Providers · Provider
▲
Idealab API Key
Kimi
▼
Enter to select, ↑↓ to navigate, Esc to go back

Third-party Providers · Provider
▲
Requesty
Xiaomi MiMo API Key
▼
Enter to select, ↑↓ to navigate, Esc to go back

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

Environment (optional)

macOS, Node.js 24, QWEN_SANDBOX=false, source CLI through npm run dev -- --screen-reader, terminal size 100×24.

Risk & Scope

  • Main risk or tradeoff: Provider endpoints and model capability metadata may evolve upstream and will need normal preset maintenance; editable model lists still let users add newer IDs without waiting for a release.
  • Not validated / out of scope: No live paid API credentials were submitted, and Windows/Linux plus interactive Web Shell/desktop walkthroughs were not run. Full CLI typecheck remains blocked in this checkout by pre-existing channel package and Ink selection type errors; changed files passed lint and the affected core, SDK, and VS Code typechecks passed.
  • Breaking changes / migration notes: None. Existing Custom Provider configurations remain valid and no credential migration is required.

Linked Issues

None.

中文说明

这个 PR 做了什么

/authThird-party Providers 中加入 Kimi 和 Xiaomi MiMo 的一等预设。Kimi 作为一个 provider 展示,并提供 Coding PlanAPI Key (China)API Key (International) 三种接入方式;Xiaomi MiMo 作为一个 provider 展示,并提供按量付费以及中国、新加坡、欧洲 Token Plan endpoint。

将 endpoint 级模型元数据贯通到 CLI、ACP、daemon/SDK、VS Code、Web Shell 和桌面端配置流程,确保每个选中的 endpoint 使用正确的默认模型和环境变量。第三方 provider 按显示名称的字典序排列,/auth 列表也会根据终端可用高度分页并显示滚动箭头。

为什么需要

此前 Kimi 和 Xiaomi MiMo 必须通过 Custom Provider 重复配置,支持的 endpoint 和订阅专用 endpoint 也不容易发现。Kimi 的 Coding Plan 与区域 API 使用不同凭据和模型目录,因此扁平的单一模型列表会为部分 endpoint 安装无效模型。

加入这些 provider 后,列表高度也超过了弹窗。旧逻辑的上限是十个逻辑 item,但每个带描述的 item 会占多行终端空间,所以外层高度约束会裁剪内容,却不会触发列表分页。

Reviewer 测试计划

如何验证

  1. 启动仓库版本 CLI,打开 /authThird-party Providers。确认 provider 名称按字典序显示、DeepSeek 仍是第一项,并且列表超过可用高度时出现 /。持续按 Down,确认 Kimi 和 Xiaomi MiMo 可以出现,底部提示不会被裁剪。
  2. 打开 Kimi。确认接入方式为 Coding PlanAPI Key (China)API Key (International)。Coding Plan 应推荐 k3-256kk3kimi-for-codingkimi-for-coding-highspeed;两个 API 选项都应推荐 kimi-k3kimi-k2.7-codekimi-k2.7-code-highspeedkimi-k2.6
  3. 打开 Xiaomi MiMo API Key。确认 endpoint 选项为按量付费、Token Plan (China)、Token Plan (Singapore) 和 Token Plan (Europe),随后推荐 mimo-v2.5-promimo-v2.5
  4. 不输入真实凭据,取消每个流程。也可以在 VS Code、Web Shell 或桌面端重复 endpoint 选择,确认 endpoint 级默认模型保持一致。

自动验证:157 个 core provider 测试通过;core build 和 typecheck 通过;413 个相关 CLI 测试通过;10 个 VS Code auth handler 测试通过;SDK 和 VS Code typecheck 通过;所有变更文件通过 ESLint 和 Prettier。

证据(Before & After)

Before: Third-party Providers 中没有 Kimi 和 Xiaomi MiMo,必须通过 Custom Provider 配置。带描述的 provider 列表可能超过受约束的弹窗高度,但逻辑 item 数仍被判断为全部可容纳,导致后面的 provider 和底部提示被裁剪。

After: 在 macOS 的 100×24 终端中通过 npm run dev -- --screen-reader 运行时,底部提示保持可见,按 Down 后两项 viewport 会持续移动:

Third-party Providers · Provider
▲
Idealab API Key
Kimi
▼
Enter to select, ↑↓ to navigate, Esc to go back

Third-party Providers · Provider
▲
Requesty
Xiaomi MiMo API Key
▼
Enter to select, ↑↓ to navigate, Esc to go back

测试平台

OS 状态
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

环境(可选)

macOS、Node.js 24、QWEN_SANDBOX=false,通过 npm run dev -- --screen-reader 运行源码 CLI,终端大小为 100×24。

风险与范围

  • 主要风险或权衡:Provider endpoint 和模型能力元数据可能在上游演进,需要按常规方式维护 preset;模型列表保持可编辑,因此用户无需等待新版本也可以添加新 ID。
  • 未验证 / 范围外:没有提交真实付费 API 凭据;没有执行 Windows/Linux 以及 Web Shell/桌面端交互式 walkthrough。此 checkout 的完整 CLI typecheck 仍被已有的 channel package 和 Ink selection 类型错误阻塞;变更文件 lint 以及受影响的 core、SDK、VS Code typecheck 均已通过。
  • Breaking changes / 迁移说明:无。现有 Custom Provider 配置继续有效,不需要迁移凭据。

关联 Issue

无。

@DragonnZhang

Copy link
Copy Markdown
Collaborator Author

E2E Test Report

Environment

  • macOS, Node.js 24
  • Repository source CLI via QWEN_SANDBOX=false npm run dev -- --screen-reader
  • Terminal size: 100×24
  • Isolated temporary Qwen settings directory

Baseline

The globally installed Qwen Code 0.21.3 did not expose Kimi or Xiaomi MiMo under /authThird-party Providers; both required manual Custom Provider setup. The expanded descriptive provider list also had no item-window pagination tied to the dialog height.

Post-change result

  • Opened /authThird-party Providers and confirmed / scroll affordances with the footer continuously visible.
  • Repeated Down input moved the visible viewport from DeepSeek/Grok to Idealab/Kimi and then to Requesty/Xiaomi MiMo without clipping.
  • Opened Kimi and confirmed one top-level provider with Coding Plan, API Key (China), and API Key (International) choices.
  • Confirmed Coding Plan and API endpoints expose their separate recommended model sets.
  • Opened Xiaomi MiMo and confirmed pay-as-you-go plus China, Singapore, and Europe Token Plan choices with MiMo V2.5 models.
  • Backed out without submitting or persisting any real credentials.

Result

✅ Passed on macOS.

@DragonnZhang
DragonnZhang marked this pull request as ready for review August 2, 2026 07:00
@DragonnZhang
DragonnZhang enabled auto-merge August 2, 2026 07:00
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Re-run gate at 3c2c1331 — after the round-19 Critical fixes (f9d446f8), the CI repair push (3c2c1331), and the maintainer's second real-environment verification of this exact head.

Template: looks good ✓

Problem: real user friction, not a theoretical concern — Kimi and Xiaomi MiMo users had to hand-recreate these endpoints through Custom Provider, and Kimi's Coding Plan vs regional APIs use different credential variables and different model catalogs, so a flat preset would install invalid models for some endpoints. The pagination fix addresses a real clipping bug: the maintainer reproduced the corruption on the base build at 100×24 and confirmed the fix on this PR's build.

Direction: aligned. First-class third-party presets are an established pattern here — the CHANGELOG records "Added xAI Grok as a built-in model provider preset" (#6805) alongside DeepSeek, MiniMax, ModelScope and others. Extending the existing preset seam to carry endpoint-specific metadata is the minimal way to express subscription-scoped endpoints.

Size: core provider paths touched across seven packages. ~1,850 production-logic lines vs ~5,750 test lines (~1:3 ratio), ~75 doc lines, ~3 CI lines. That is far past the 500-line core threshold, so the Stage 0 maintainer-awareness escalation applies; it has been thoroughly exercised — 20 review rounds, a takeover loop, and maintainer live verification ending in an approval at this commit. The 1000+ line large-PR advisory applies too, but splitting an already-converged review would cost more than it saves — informational only.

Approach: the endpoint metadata rides on the existing preset seam (BaseUrlOption.models + a resolver + endpoint-scoped metadata keys) instead of a parallel mechanism, and all six client surfaces consume that one source. Alphabetical ordering and height-based pagination are small and contained. Nothing unrelated to the stated goal stands out.

Risk: packages/cli/src/acp-integration/ matches a revert-correlated path pattern, so no review depth was skipped. The actual change there is confined to provider catalog/config serialization — no agent or connection lifecycle changes — and it is covered by unit tests, green CI, and the maintainer's live drive.

Moving on to code review. 🔍

中文说明

3c2c1331 上重新执行准入检查——此时第 19 轮 Critical 修复(f9d446f8)、CI 修复推送(3c2c1331)以及维护者对该 head 的第二次真实环境验证均已完成。

**模板:**完整 ✓

**问题:**真实用户摩擦,不是理论问题——Kimi 和 Xiaomi MiMo 用户此前必须通过 Custom Provider 手工重建这些 endpoint,且 Kimi 的 Coding Plan 与区域 API 使用不同的凭据变量和模型目录,扁平预设会为部分 endpoint 装入无效模型。分页修复针对的是真实的裁剪 bug:维护者在 base 版本上于 100×24 复现了串行,并确认本 PR 已修复。

**方向:**对齐。一等第三方预设是既有模式——CHANGELOG 中有"Added xAI Grok as a built-in model provider preset"(#6805),以及 DeepSeek、MiniMax、ModelScope 等先例。在既有预设接缝上扩展 endpoint 级元数据,是表达订阅制 endpoint 的最小方式。

**规模:**触及七个包的核心 provider 路径。生产逻辑约 1,850 行,测试约 5,750 行(约 1:3),文档约 75 行,CI 约 3 行。远超 500 行核心阈值,Stage 0 维护者知悉升级适用且已被充分执行——20 轮评审、takeover 循环、维护者真机验证,最终在本 commit 上给出 approval。1000+ 行大 PR 提示同样适用,但此时拆分已收敛的评审得不偿失——仅作信息提示。

**方案:**endpoint 元数据走既有预设接缝(BaseUrlOption.models + resolver + endpoint 级 metadata key),六个客户端面共用同一数据源,没有平行机制。字典序排序与按高度分页小而收敛。未见与目标无关的改动。

风险:packages/cli/src/acp-integration/ 命中与 revert 相关的路径模式,因此未跳过任何审查深度。该处实际改动限于 provider 目录/配置序列化——不涉及 agent 或连接生命周期——有单测、绿色 CI 与维护者真机操作覆盖。

进入代码审查。🔍

Qwen Code · qwen3.8-max

Reviewed at 3c2c1331aeae2b0f1dee44861801628d942f6207 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Code review (re-run at 3c2c1331)

Independent proposal: before reading the diff I'd have done this: two new preset files following the existing preset pattern; since Kimi's three access types and MiMo's four endpoints need different base URLs, env keys and model catalogs, extend BaseUrlOption with optional per-endpoint models plus a resolver mapping (provider, baseUrl) → models; scope providerMetadata keys per endpoint so sibling installs don't overwrite each other, with a legacy-key fallback for existing presets; thread the metadata through serve/ACP/VS Code/web-shell/desktop; fix the list-height pagination.

Comparison: the PR matches this shape almost exactly and goes further where it matters. resolveProviderModels + BaseUrlOption.models is the seam; resolveMetadataKey gains a stable provider--endpoint suffix (with . escaping against dotted-path writes); the version hash now tracks the provider's built-in template rather than the user's selection, so a deselected default never re-triggers the update prompt; and applyModelProvidersPatch replaces models in place at the first removed position instead of prepending, so re-submitting one endpoint can't silently reorder or delete a sibling. Secrets handling improved along the way: the ACP/desktop wire types replaced a serializable existingConfig.apiKey with a boolean hasApiKey, and the serve catalog degrades per-provider (a throwing derivation only costs that provider its derived field, not the whole catalog).

Critical blockers: none found. This head already absorbed 20 review rounds; the round-19 Criticals were fixed in f9d446f8 and the duplicate-import CI breakage in 3c2c1331.

Non-blocking observations:

  • Six round-20 Suggestions remain open (the automated reviewer's last pass, all severity S). After 20 rounds the right move per the anti-balloon guidance is to defer them to a follow-up rather than spin another round. The two most substantive: the endpoint-restore edge cases in AuthDialog (saved models without a baseUrl fold into the restored endpoint; a saved baseUrl matching no shipped option falls back to provider-wide defaults — data-preserving, just coarse), and the near-duplicate endpoint-state helpers in the desktop and web-shell packages (apiKeyAfterBaseUrlChange & co.), which live in separate packages with different wire types and are hard to share today.
  • In kimi.ts the endpoint documentation URLs appear both in the baseUrl options and again in the top-level documentationUrl function — harmless, but the function could look the option up to keep one source.
  • Follow-up candidates (both confirmed by the maintainer's verification): ModelIdsStep still clips below ~30 terminal rows — pre-existing, reproduces on the base build; and the legacy providerMetadata.<id> key is left behind after migration to the endpoint-suffixed key — harmless, never read again for multi-endpoint providers.
Files changed (30 of 58 shown)
File What changed
packages/core/src/providers/types.ts BaseUrlOption gains optional per-endpoint models; install patch gains cross-endpoint retain/own fields
packages/core/src/providers/presets/kimi.ts New preset: Coding Plan plus China and International API endpoints with per-endpoint models, env keys, doc links
packages/core/src/providers/presets/xiaomi-mimo.ts New preset: pay-as-you-go plus three Token Plan endpoints sharing one model list
packages/core/src/providers/provider-config.ts resolveProviderModels, endpoint-scoped metadata keys, template-based version hash, exported baseUrl normalization
packages/core/src/providers/install.ts Endpoint-safe merge: replace in place at the first removed slot; keep the current model across sibling endpoints
packages/core/src/providers/all-providers.ts Registers the two providers; third-party list sorted by label
packages/core/src/providers/index.ts Exports the new presets and resolvers
packages/core/src/providers/presets/alibaba-coding-plan.ts Opts into identity merge so both regions share one auth type safely
packages/core/src/providers/presets/alibaba-token-plan.ts Same opt-in for the Token Plan regions
packages/core/src/telemetry/gen-ai-provider.ts Recognizes the new endpoints for telemetry labels, with attacker-domain guard tests
packages/cli/src/ui/auth/AuthDialog.tsx Height-based list pagination with scroll arrows; endpoint-scoped restore of saved setup
packages/cli/src/ui/auth/useProviderSetupFlow.ts Endpoint switching preserves key drafts, custom-model provenance and per-endpoint trimmed defaults
packages/cli/src/ui/auth/ProviderSetupSteps.tsx Model step options follow the selected endpoint; protocol step restores the saved protocol
packages/cli/src/ui/hooks/useProviderUpdates.ts Per-endpoint update targets, one-time legacy-key migration, endpoint-scoped re-install and re-auth guard
packages/cli/src/ui/components/ProviderUpdatePrompt.tsx Labels each endpoint section; metadataKey as the React key
packages/cli/src/ui/components/DialogManager.tsx Passes available terminal height into the auth dialog
packages/cli/src/ui/components/shared/DescriptiveRadioButtonSelect.tsx Truncates long descriptions instead of wrapping
packages/cli/src/serve/server/auth-provider-helpers.ts Catalog carries per-option envKey and models; a throwing provider degrades only itself
packages/cli/src/serve/run-qwen-serve.ts Install requests default to the endpoint-specific model IDs
packages/cli/src/acp-integration/acpAgent.ts Seeds modelIds scoped to the restored endpoint; exposes modelIdsByBaseUrl; hasApiKey instead of key values
packages/vscode-ide-companion/src/services/settingsWriter.ts Sign-out clears function-derived env keys and endpoint-suffixed metadata keys
packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts Models step seeded with endpoint defaults plus restored custom models
packages/web-shell/client/components/messages/AuthMessage.tsx Per-endpoint env key, models and doc link; modelsDirty guards user edits across endpoint switches
packages/web-shell/client/components/messages/auth-provider-state.ts Pure endpoint-state helpers, fully unit tested
packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.ts Desktop twin of the endpoint-state helpers, fully unit tested
packages/desktop/apps/electron/src/renderer/components/apisetup/ProviderConnectForm.tsx Wires endpoint switching and model editing through provider-state
packages/desktop/packages/shared/src/protocol/dto.ts Wire types gain per-option envKey/models; existingConfig.apiKey replaced by hasApiKey
docs/design/kimi-xiaomi-auth-providers.md Design doc with model metadata rationale and sources
.github/workflows/ci.yml Scrubs the three new env keys in the no-AK integration job
…and 24 more files Unit/integration tests (~5,750 lines) covering everything above, plus doc and SDK-type updates

Testing

CI evidence (this commit's own runs, via API — no PR code was executed by triage):

Check Conclusion
Test (ubuntu-latest, Node 22.x) ✅ success
Test (macos-latest, Node 22.x) ⏭️ skipped — merge-queue-only job (event_name == 'merge_group'), skipped on every PR
Test (windows-latest, Node 22.x) ⏭️ skipped — merge-queue-only job, same reason
Integration Tests (CLI, No Sandbox) ⏭️ skipped — merge-queue-only job, same reason
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Serve A/B (ubuntu-latest, Node 22.x) ✅ success — no response changes vs the PR base across 4 scenarios
Capture web-shell visuals ✅ success
Live Host (macos-latest) ✅ success
Real daemon E2E (SDK Java) ✅ success
precheck-pr / precheck ✅ success

All pull_request-event workflow runs on this commit are complete; nothing is pending. The three skipped test jobs are merge-queue-only by workflow design, not a gap in this PR. Not verified by triage: the macOS/Windows platform legs and the integration suite never run at PR stage for any PR — they will run in the merge queue.

Behavioural claims. The central claims are behavioural (endpoint routing, per-endpoint model lists, migration of existing installs), and they were verified on this exact head by the maintainer's real-environment report above in this thread: live CLI TUI + qwen serve + Web Shell against the real Kimi/MiMo endpoints, per-endpoint 401 wire proof, and an Alibaba-legacy upgrade path that migrated with a byte-identical result. That is maintainer evidence, not something this triage run re-executed — unattended CI never runs PR code. The sandboxed verification run triggered by the same command (run 31608893329) is still in flight and will post its own report here; if a bot-driven TUI capture is also wanted, a maintainer can trigger the isolated @qwen-code /tmux job.

中文说明

代码审查(在 3c2c1331 上重新执行)

**独立方案:**读 diff 之前我会这样做:按既有预设模式新增两个 preset 文件;由于 Kimi 的三种接入方式与 MiMo 的四个 endpoint 需要不同的 base URL、env key 和模型目录,在 BaseUrlOption 上增加可选的 endpoint 级 models,并加一个 (provider, baseUrl) → models 的 resolver;把 providerMetadata key 按 endpoint 分隔以免互相覆盖,并为已有预设保留旧 key 回退;把元数据贯通 serve/ACP/VS Code/web-shell/desktop;修复列表高度分页。

**对比:**PR 的实现与这个方案几乎完全一致,并在关键处做得更深:resolveProviderModels + BaseUrlOption.models 作为接缝;resolveMetadataKey 增加稳定的 provider--endpoint 后缀(并转义 . 防止点路径写入);version 哈希改为跟踪 provider 内置模板而非用户选择,取消勾选默认模型不会再反复触发更新提示;applyModelProvidersPatch 在首个被移除位置原位替换而不是前置,重提一个 endpoint 不会静默重排或删除兄弟 endpoint。密钥处理也顺带收紧:ACP/桌面的 wire 类型把可序列化的 existingConfig.apiKey 换成布尔 hasApiKey;serve 目录按 provider 降级(抛错的推导只影响该 provider 自身)。

**Critical 阻断项:未发现。**本 head 已吸收 20 轮评审;第 19 轮 Critical 已在 f9d446f8 修复,重复 import 的 CI 问题已在 3c2c1331 修复。

非阻断观察:

  • 第 20 轮仍有 6 条 Suggestion 未处理(均为 S 级)。20 轮之后按反膨胀原则应转入后续 issue,而不是再来一轮。其中较实质的两条:AuthDialog 的 endpoint 恢复边界情形(无 baseUrl 的已存模型并入恢复的 endpoint;已存 baseUrl 不匹配任何内置选项时回退到 provider 全量默认——不丢数据,只是粗粒度);以及桌面与 web-shell 两个包中几乎重复的 endpoint 状态助手函数(分属不同包、wire 类型不同,目前难以共享)。
  • kimi.ts 中 endpoint 文档 URL 同时出现在 baseUrl 选项和顶层 documentationUrl 函数里——无害,但函数可以直接查选项,保持单一来源。
  • 建议单独开 issue 跟进(均经维护者验证确认):ModelIdsStep 在约 30 行以下的终端仍会裁剪——已有问题,base 版本同样复现;迁移到 endpoint 后缀 key 后旧 providerMetadata.<id> key 会残留——无害,多 endpoint provider 不再读取。

测试

**CI 证据(本 commit 自己的运行,经 API 获取——triage 未执行任何 PR 代码):**见上方英文表格。所有 pull_request 事件的工作流运行均已完成,无 pending。三个 skipped 的测试 job 是工作流设计上仅在 merge queue 运行,不是本 PR 的缺口。triage 未验证:macOS/Windows 平台腿和集成套件在任何 PR 阶段都不运行,将在 merge queue 中执行。

**行为性声明。**核心声明是行为性的(endpoint 路由、endpoint 级模型列表、存量安装迁移),且已由维护者在本帖上方的真实环境报告中于本 head 上验证:真实 CLI TUI + qwen serve + Web Shell 对接真实 Kimi/MiMo endpoint、按 endpoint 区分的 401 wire 证明、以及逐字节一致的 Alibaba 旧版升级路径。那是维护者的证据,不是本次 triage 运行重新执行的——无人值守 CI 从不运行 PR 代码。由同一命令触发的沙箱验证运行(run 31608893329)仍在进行,完成后会在此发布报告;如还需要机器人驱动的 TUI 抓取,维护者可触发隔离的 @qwen-code /tmux job。

Qwen Code · qwen3.8-max

Reviewed at 3c2c1331aeae2b0f1dee44861801628d942f6207 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Confidence: 3/5 — clean re-review at 3c2c1331 with no open Criticals; the cap is pure policy, not doubt — a fork feat touching core infrastructure at this scale (~1,850 production lines across seven packages) is Stage 0's maintainer-escalation case, and the gate never casts the deciding approval on one of those.

Stepping back: the implementation matches or exceeds my independent proposal at every point, the test-to-production ratio is roughly 3:1, and the design chose the hard-but-right options — template-based version hashes, endpoint-scoped ownership, in-place merge positions, hasApiKey instead of key values on the wire. Twenty review rounds plus a takeover loop have converged it: the round-19 Criticals are fixed, CI on this head is green, and the remaining round-20 items are Suggestions that belong in a follow-up, not another round. The maintainer then verified it end to end in a real environment at this exact commit — endpoint routing, model lists, and the legacy-Alibaba upgrade path — and approved it.

⏸️ Deferring to @wenshao — policy cap, no code blockers. Because Stage 0 escalated this PR for maintainer awareness, the triage gate does not approve it regardless of how clean the stages look; the merge decision stays human. Concretely, two housekeeping items stand between this PR and merge:

  1. The standing CHANGES_REQUESTED in the review decision is a bot review anchored at an older commit (e9a7eba5, Aug 11) — seventeen fix-rounds and a green CI run ago. The bot's latest pass at the current head is COMMENTED, so a maintainer may need to dismiss that stale review before branch protection will allow merging.
  2. main requires two approving reviews; @wenshao's approval at 3c2c1331 is one. If the second must also be human, that is the remaining sign-off.

If it were my call on the code alone, this would be a 4/5 approve — the two held-back points are the policy cap and the open Suggestions backlog, neither of which reflects doubt about what is on this commit.

中文说明

置信度:3/5 —— 在 3c2c1331 上的复审是干净的,没有未解决的 Critical;封顶是纯政策原因而非疑虑——一个触及核心基础设施、规模达约 1,850 行生产代码(跨七个包)的 fork feat PR 属于 Stage 0 的维护者升级情形,门禁不会为此类 PR 投出决定性的 approve。

退一步看整体:实现在每一点上都达到或超过我的独立方案,测试与生产代码比例约 3:1,设计上选择了难但正确的选项——基于模板的 version 哈希、endpoint 级 ownership、原位合并位置、wire 上用 hasApiKey 而不是密钥值。20 轮评审加 takeover 循环已使其收敛:第 19 轮 Critical 已修复,本 head 的 CI 是绿的,剩余的第 20 轮条目都是应转入后续 issue 的 Suggestion,而不是再来一轮。维护者随后在真实环境中于本 commit 上做了端到端验证——endpoint 路由、模型列表、Alibaba 旧版升级路径——并已 approve。

⏸️ **转交 @wenshao —— 政策封顶,无代码阻断项。**由于 Stage 0 已将本 PR 升级为维护者知悉,无论各阶段多干净,triage 门禁都不会批准它;合并决定保留给人类。具体来说,合并前有两件事需要处理:

  1. 当前 review 决定中的 CHANGES_REQUESTED 是锚定在旧 commit(e9a7eba5,8 月 11 日)上的 bot 评审——距现在已过去 17 轮修复和一次绿色 CI。bot 在当前 head 上的最新评审是 COMMENTED,因此维护者可能需要先驳回那条过期评审,分支保护才会放行合并。
  2. main 需要两个 approving review;@wenshao3c2c1331 上的 approval 是其中一个。如果第二个也必须是人类,那就是剩下的签署。

如果只看代码本身,我会给 4/5 并批准——保留的两点是政策封顶和未处理的 Suggestion 积压,两者都不代表对本 commit 内容的疑虑。

Qwen Code · qwen3.8-max

Reviewed at 3c2c1331aeae2b0f1dee44861801628d942f6207 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

🖼️ web-shell visual preview

Rendered against a mock daemon (no real backend): the PR base vs this PR head 92e345e. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

⚠️ No preview: one or more scenarios failed to render on this head — see the workflow run. This is not "no visual change" — a scenario that times out or throws produces no image. Fix the failing scenario (or a genuine regression it caught) and the preview returns on the next push.

Full-resolution recordings (.webm) are attached to the workflow run.

Qwen Code · web-shell visuals

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

Built the PR base vs this PR head 92e345e, drove a fixed endpoint set against each, and diffed the JSON responses. Only fields that changed are shown.

No response changes against the PR base across 12 scenario(s).

Qwen Code · serve A/B

@wenshao

wenshao commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Review: feat(auth): add Kimi and Xiaomi MiMo providers

Overview

Two new third-party presets (kimiProvider, xiaomiMimoProvider) plus a genuinely useful generalization: BaseUrlOption.models lets a single preset carry per-endpoint model catalogs. The new resolveProviderModels(config, baseUrl) is threaded through buildModelConfigs / buildProviderTemplate / getDefaultModelIds in core, and then consistently through all five setup surfaces (CLI /auth, ACP, qwen serve/daemon, VS Code, Web Shell, desktop). The third-party registry is sorted alphabetically, and AuthDialog gained height-aware pagination. Design doc + sources are included.

The plumbing is thorough — I checked every getDefaultModelIds( call site and the baseUrl-less ones (AuthDialog.tsx:226, useProviderUpdates.ts:181,244) are all deliberately the "all built-in IDs" use, so nothing was missed. Comments below are mostly about edge cases and the implicit invariants the new shape introduces.


Correctness

1. selectBaseUrl discards user input when the same endpoint is re-confirmedpackages/cli/src/ui/auth/useProviderSetupFlow.ts:222

The handler unconditionally rewrites modelIds and apiKey on every endpoint selection. Repro: pick an endpoint → type an API key (or tick/untick models) → Esc back to the endpoint step → Enter on the same endpoint. The typed key is replaced by existingProviderEnv[envKey] ?? '' and the model edits are rebuilt from defaults. This affects every multi-endpoint preset (MiniMax, Alibaba Token Plan, …), not just Kimi. Suggest gating on an actual change:

if (provider && selectedUrl !== baseUrl) { /* reset models + key */ }

Web Shell has the same issue and no env restore — AuthMessage.tsx:475 and :551 call setApiKey('') unconditionally, so re-confirming the endpoint always wipes the typed key. Desktop (onValueChange) is fine since Select only fires on change.

2. builtInIds is computed three different ways — CLI vs desktop vs web shell

  • useProviderSetupFlow.ts:227provider.models only
  • ProviderConnectForm.tsx modelIdsAfterBaseUrlChangeprovider.models ∪ all baseUrl[].models
  • AuthMessage.tsx baseUrlOptionModelIdsprovider.models ∪ all baseUrl[].models

The CLI version is only correct today because kimiProvider.models happens to be [...KIMI_CODE_MODELS, ...KIMI_API_MODELS]. Nothing enforces that invariant — a future preset that lists models only on its BaseUrlOptions would make the CLI classify the other endpoint's built-ins as "user custom IDs" and carry them across endpoints. Worth (a) exporting one core helper (getAllProviderModelIds(config)) and using it in all three places, and (b) documenting on BaseUrlOption.models that ProviderConfig.models must remain the union.

3. getDefaultModelIds(config) vs getDefaultModelIds(config, url) now mean different thingsprovider-config.ts:361

Omitting baseUrl returns the union across endpoints; passing one returns that endpoint's list. Both meanings are used intentionally in this PR, but neither function has a doc comment saying so. Given how easy it is to drop the argument, please add JSDoc to resolveProviderModels/getDefaultModelIds.

Related: with an unmatched baseUrl, resolveProviderModels falls through resolveBaseUrl to config.baseUrl[0] and returns the first option's models, not config.models. Probably intended (it mirrors what the install would actually use), but it's surprising from the name — worth a comment.

4. Kimi's two endpoints can't coexistpresets/kimi.ts:71

ownsKimiModel matches both [Kimi Code]/KIMI_CODE_API_KEY and [Kimi API]/MOONSHOT_API_KEY, and buildInstallPlan uses prepend-and-remove-owned. So installing Coding Plan after the Open Platform API (or vice versa) removes the other endpoint's models, and providerMetadata.kimi.baseUrl only records the last one. A user who has both will also see the auto-update prompt in useProviderUpdates offering to remove 4 models when only the other endpoint's list changed. Unlike MiniMax/Token Plan (shared credential + shared catalog), these two are separate subscriptions with separate keys, so coexistence is plausible. Either set mergeModelsByIdentity: true, or state in the design doc that the access types are mutually exclusive.

5. Wire-protocol semantics change for descriptor.modelsauth-provider-helpers.ts:70, acpAgent.ts:2019

Top-level models / defaultModelIds now resolve against the first base-URL option instead of provider.models. For Kimi, daemon/ACP clients see only the 4 Coding Plan IDs at the top level. Any existing client using descriptor.models as "the provider's full catalog" (e.g. to split built-in vs custom IDs) will now misclassify. Please document the new meaning on ServeAuthProviderDescriptor.models, DaemonAuthProviderDescriptor.models, and QwenProviderSummary.models — the field is only additive-safe for the per-option models, not for this one.


UI / pagination

6. Fixed-row constants don't cover the error bannerAuthDialog.tsx:131

MAIN_LIST_FIXED_ROWS = 10 is measured for the error-free main view, but authError/errorMessage adds rows, so the exact case the pagination was added to fix can still clip. Also, because the reservation is large, dialogHeight ≤ 18 collapses the 3-item main menu to a single visible item (floor((18-10-4)/3) = 1). Consider dropping the separator + ToS block when height-constrained instead of shrinking the list to one row — that chrome is what's consuming the budget.

7. Theme color is frozen at module loadAuthDialog.tsx:51

MAIN_ITEMS is a module-level constant whose descriptions are now JSX reading theme.text.secondary. theme is a live getter proxy (semantic-colors.ts), but the value is captured once when the module is imported at CLI startup. Previously the description was a plain string and DescriptiveRadioButtonSelect applied the live theme at render time, so this is a small regression: change the theme, reopen /auth, and the three main-menu descriptions keep the startup color. (providerToItem is fine — the dialog unmounts on close, so its useMemo(…, []) re-runs.) Building MAIN_ITEMS inside the component, or keeping the string and letting the list component apply wrap="truncate", both fix it.


Tests

Good additions: preset metadata/install-plan tests, registry ordering, serve-helper serialization, endpoint-scoped update in useProviderUpdates, ACP list payload.

Gaps and nits:

  • The riskiest new CLI logic is untested. selectBaseUrl's model/API-key reset (issue 1 & 2) has no unit test. A renderHook test over useProviderSetupFlow covering "switch endpoint → defaults swap, custom IDs preserved" and "re-select same endpoint → typed key preserved" would pin both.
  • AuthDialog.test.tsx — the third-party test flipped from "shows the presets" to not.toContain('MiniMax API Key') / not.toContain('Z.AI API Key'). Nothing now asserts every third-party preset is reachable. Consider keeping a THIRD_PARTY_PROVIDERS-driven assertion (list membership, not frame text) and adding a scroll-down test that Kimi/Xiaomi MiMo become visible — the PR body verifies that manually only.
  • expect(frame?.split('\n')).toHaveLength(17) is brittle against any layout change; asserting "no more than the budget" would be more durable.
  • createSettings() duplicates the inline LoadedSettings construction already present later in the same file — worth reusing one helper.
  • all-providers.test.ts asserts the declaration order of ALL_PROVIDERS is alphabetical. That's a reasonable lint, but note the sort key is the English label while the UI renders t(config.label) — under a locale that translates labels the displayed order won't be alphabetical.
  • Model metadata (k3-256k = 262,144 tokens, mimo-v2.5-pro text-only, which IDs are thinkingMandatory) can't be verified from the repo. Since a wrong thinkingMandatory silently changes request shape, it'd be good to have a second reviewer confirm against the linked docs.

Style / conventions

  • Presets match the existing deepseek.ts/grok.ts/minimax.ts shape; license headers, exported *_ENV_KEY constants, and uiGroup are all consistent. 👍
  • serializeProviderModel extraction in auth-provider-helpers.ts is a clean dedup.
  • Minor asymmetry: label: 'Kimi' vs 'Xiaomi MiMo API Key' / 'MiniMax API Key'. Justified (Kimi isn't API-key-only), just noting it — the docs list already reflects it.
  • serializeProviderModel drops thinkingMandatory and imageOnly; pre-existing for top-level models, but it now also applies to the per-option lists, so remote clients never see those flags. Fine since the install resolves server-side — just confirming it's intentional.

Security / performance

Nothing concerning. API keys keep the existing env-var storage path, are cleared rather than leaked on endpoint switch, and aren't logged. THIRD_PARTY_PROVIDERS.sort() runs once at module load on a filter() copy (doesn't mutate ALL_PROVIDERS); resolveProviderModels is a small linear scan behind useMemo.


Summary

Solid, well-scoped feature with the cross-surface plumbing done carefully. The blocking-ish items for me are #1 (input loss when re-confirming an endpoint — user-visible and easy to hit) and #2/#3 (the unenforced "models is the union" invariant plus the two meanings of getDefaultModelIds, which is the kind of thing the next preset will get wrong). #4 and #5 are decisions to make explicit rather than defects. The rest are polish.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

中文说明

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

— qwen3.8-max-preview via Qwen Code /review

Comment thread packages/cli/src/ui/auth/AuthDialog.tsx
Comment thread packages/core/src/providers/all-providers.ts
Comment thread packages/cli/src/ui/auth/useProviderSetupFlow.ts Outdated
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/core/src/providers/all-providers.ts
Comment thread packages/core/src/providers/presets/kimi.ts
wenshao added a commit that referenced this pull request Aug 2, 2026
…t it

A mutant or hunk whose own collocated test was not green in the unmutated
baseline is held `inconclusive` -- correctly, since the other probes passing
shows only that THEY do not cover it. But both guards then named a cause they
had not measured: "likely a compile or import error in the probe tree".

There are two ways a probe is not green and they are different failures with
different fixes. Measured on PR #8368: `AuthDialog.test.tsx` compiled fine,
collected 26 tests and failed exactly one, and all three mutants in its source
were held with the import-error wording -- sending a reader after a problem
that was never there. The baseline had already classified it `gated` (a real
assertion failure) rather than `inconclusive` (collected nothing); the guards
just did not look.

Both now build their detail from one exported function that reads the verdict
off the baseline, so the two sentences cannot drift apart again and what the
tests pin is the string the report carries. A probe with no baseline entry
takes the collected-nothing wording: absent is an evidentiary hole, never the
claim that its tests failed.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Suggestions are inline. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally. Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查。 建议见行内评论。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

— qwen3.8-max-preview via Qwen Code /review (v0.21.3)

Comment thread packages/cli/src/acp-integration/acpAgent.test.ts Outdated
@wenshao

wenshao commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Review round 2: feat(auth): add Kimi and Xiaomi MiMo providers

Re-reviewed the full diff at c55523f, focused on what fix(auth): address endpoint provider review feedback changed since round 1.

What the follow-up commit fixed ✅

  • KIMI_CODE_API_KEY / MOONSHOT_API_KEY / MIMO_API_KEY wired into ci.yml + no-ak-integration-ci.test.js — good catch, this was missing.
  • clearPersistedAuth now clears function-derived env keys (settingsWriter.ts:685), so a Kimi logout actually removes both keys instead of neither.
  • Per-endpoint envKey added to the serve/daemon catalog + web shell review preview, so Kimi's review screen names the right variable.
  • buildProviderSetupInputs exported and unit-tested; useProviderSetupFlow.test.ts added.

New issues introduced by the follow-up commit

A. The envKey resolution regresses the Custom Provider descriptorpackages/cli/src/serve/server/auth-provider-helpers.ts:52

const envKey =
  typeof provider.envKey === 'function'
    ? provider.envKey(provider.protocol, defaultBaseUrl)
    : provider.envKey;
...
...(envKey ? { envKey } : {}),

buildAuthProviderCatalog maps all of ALL_PROVIDERS, and customProvider has baseUrl: undefinedresolveBaseUrl(provider) returns '' → this calls generateCustomEnvKey(USE_OPENAI, '') and emits a real-looking but meaningless QWEN_CUSTOM_API_KEY_OPENAI__<hash-of-empty-url> on the descriptor.

The old guard (typeof provider.envKey === 'string') omitted it, and web shell fell back correctly. Now selectedBaseUrlEnvKey (AuthMessage.tsx:108) hits provider.envKey ?? … first, so the Custom Provider review preview shows the wrong env var name — previously OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY per the chosen protocol, now a hash key that will never exist. The persisted config is still correct (the install resolves server-side), but the preview lies to the user.

Suggested fix — only derive the top-level key when the provider actually has a fixed endpoint:

const envKey =
  typeof provider.envKey === 'string'
    ? provider.envKey
    : provider.baseUrl !== undefined
      ? provider.envKey(provider.protocol, defaultBaseUrl)
      : undefined;

The per-option envKey mapping below it is fine as-is (custom provider has no options).

B. clearPersistedAuth's new loop runs the custom provider through an empty base URLsettingsWriter.ts:689

const baseUrls = Array.isArray(p.baseUrl) ?  : [p.baseUrl ?? ''];

Same '' path: for customProvider this derives and deletes 3 hash keys that can never exist (one per protocolOptions entry). Harmless but confusing given the comment two lines below already says custom-provider keys are swept by prefix. if (p.baseUrl === undefined) continue; before the loop makes the intent explicit.

C. Kimi is invisible to GenAI telemetrypackages/core/src/telemetry/gen-ai-provider.ts:22,44

MIMO_API_KEY / XIAOMI_MIMO_API_KEY and xiaomimimo.com are already mapped, so MiMo is covered. Kimi is not: neither MOONSHOT_API_KEY nor KIMI_CODE_API_KEY is in PROVIDER_BY_ENV_KEY, and providerFromHostname has no case for kimi.com / moonshot.cn / moonshot.ai. resolveGenAiProviderName therefore falls through to authType: 'openai' and every Kimi request is attributed to provider openai in telemetry. Two lines in each table fixes it (moonshot is the semconv name).

D. Doc links are dead for both new presets

auth-provider-helpers.ts:61 only serializes documentationUrl when it's a string. Kimi and MiMo use the function form, so daemon/web-shell clients get no documentation link at all — every other preset shows one. Separately, ACP resolves it once against defaultBaseUrl (acpAgent.ts:2020), so desktop always shows the Kimi Code docs even after the user picks the Moonshot endpoint.

Meanwhile the per-option documentationUrl you added in kimi.ts / xiaomi-mimo.ts is never read anywhere: BaseUrlSelectStep (ProviderSetupSteps.tsx:60) ignores it, and nothing serializes it. Every other multi-endpoint preset (minimax, zai, alibaba-*) puts docs only on the option and has no provider-level function — I'd match that and either drop the function form, or teach the two serializers to resolve per-endpoint. As written it's two sources of truth, both unused on some surfaces.

E. Test-timing band-aids in shared helpersAuthDialog.test.tsx:187,195,203,205

pressEnterAndWaitFor and moveDownAndWaitForSelection gained unconditional setTimeout(50) on both sides, plus extra await wait() at half a dozen call sites. These are shared helpers used across the whole file, so this adds fixed latency to every navigation test and papers over whatever race actually needed it rather than naming it. If the real problem is that ink hasn't flushed the frame before the next keypress, a vi.waitFor on the selected row (which waitForSelectedOption already does) should be sufficient — worth a comment explaining what the sleep is waiting for if it has to stay.

Related: the new loop drives Down through ['Grok (xAI) API Key', 'Idealab API Key', 'Kimi', 'MiniMax API Key'] to reach MiniMax. That hard-codes the alphabetical registry order, so the next preset added between D and M breaks an unrelated test. A "press Down until MiniMax API Key is selected, max N times" loop is order-independent.

Still open from round 1

  • pre-release: fix ci #1selectBaseUrl discards typed input when the same endpoint is re-confirmed (useProviderSetupFlow.ts:223). The handler still resets unconditionally; web shell (AuthMessage.tsx:473, :549) still calls setApiKey('') unconditionally with no env restore. Repro is unchanged: pick endpoint → type key → EscEnter on the same endpoint → key gone. A selectedUrl !== baseUrl guard is still the smallest fix. This was my main blocking item.
  • Where is the config saved? #2 — three different builtInIds computations. useProviderSetupFlow.ts:227 still uses provider.models only, while desktop and web shell union it with all baseUrl[].models. Still correct only because kimiProvider.models happens to be the union. One exported core helper would settle it.
  • 如何自定义密钥文件 .env可能与其他文件冲突 #3 — no JSDoc on resolveProviderModels / getDefaultModelIds. The with-arg vs without-arg meanings still differ silently, and the unmatched-baseUrl fallback (returns the first option's models via resolveBaseUrl, not config.models) is still undocumented.
  • Are you interested in AI Terminal? #4 — Kimi's two access types can't coexist (ownsKimiModel matches both prefixes + prepend-and-remove-owned). Still no mergeModelsByIdentity and no note in the design doc.
  • TypeError in Authentication Selection Interface #5descriptor.models semantics changed (now the first endpoint's list, not the full catalog) with no doc comment on ServeAuthProviderDescriptor / DaemonAuthProviderDescriptor / QwenProviderSummary.
  • OpenAI API Error: 401 Incorecct API Key provided #6MAIN_LIST_FIXED_ROWS / SUB_MENU_LIST_FIXED_ROWS still ignore the error banner. I re-counted the chrome: 10 and 7 are exactly right for the error-free view, and authError || errorMessage adds marginTop 1 + at least 1 text row (more when it wraps). Since DialogManager renders this dialog precisely because uiState.auth.authError is set, the clipping this PR fixes returns in the most common failure path. Also worth a comment deriving the constants — right now they're unexplained magic numbers that any chrome change silently invalidates.
  • API Key是要设成阿里云的API Key吗? #7theme.text.secondary frozen at module load in MAIN_ITEMS. Unchanged. Adding wrap="truncate" to the string branch of DescriptiveRadioButtonSelect.tsx:75 is a one-line fix that keeps the live theme and helps every other dialog too.

Test coverage

useProviderSetupFlow.test.ts is a good addition and pins the switch-endpoint path (defaults swap, custom IDs preserved, key restored from env). It does not cover the case that's actually broken — re-selecting the same endpoint after typing a key. Worth adding alongside the fix for #1, since a passing switch-endpoint test currently reads as "this area is covered".

buildProviderSetupInputs test and the envKey assertions in auth-provider-helpers.test.ts are well targeted. The latter would have caught issue A with one more line: expect(catalog.providers.find(p => p.id === 'custom-openai-compatible')?.envKey).toBeUndefined().

Security / performance

Nothing new. Keys still live in the env-var path, are cleared rather than leaked on endpoint switch, and aren't logged. The clearPersistedAuth loop is bounded by preset count. No new network calls.

Summary

The follow-up commit closed the CI-env-key and logout gaps cleanly. Remaining blockers for me:

  1. A — new regression: bogus envKey on the Custom Provider descriptor, user-visible in the web shell review preview.
  2. pre-release: fix ci #1 (round 1) — still loses typed input on endpoint re-confirm, in both CLI and web shell.
  3. C — Kimi mis-attributed as openai in telemetry; two-line fix, easy to forget later.

#2/#3 (the unenforced "models is the union" invariant) remain the thing the next preset author will get wrong. D, E, #4#7 are polish / decisions to make explicit.

wenshao added a commit that referenced this pull request Aug 2, 2026
… them

The hold landed downstream of the thing it exists to correct. In the skill's
order `compose-review` ran first, so a Critical held back afterwards reached
only the Step 8 report: the verdict line, the drafted `**[Critical]**` marker
and the payload `submit` recounts were all fixed before the measurement was
consulted. That is the exact path the #8368 misattribution took into a composed
review, and this change had not closed it. The findings artifact is now written
before the verdict, and a hold arriving later is named as the comment-set
change it is.

`heldByMeasurement` did not survive `--input`. `validateFindings` builds from a
whitelist and never copied it, so the field a later round was supposed to read
lasted exactly one command and `counts.held` fell back to zero -- the same
invariant `outcomeNote` was added a few lines above to satisfy.

`locations[].file` left the haystack, for a sharper version of the reason
`suggestedFix` did. A finding ABOUT a test's content carries that test as its
location, and a PR touching an already-red test is precisely when such a
finding is written; demoting it uses the measurement against a claim the
measurement does not address.

The no-`entries` fallback is gone. It qualified nothing, so it put back the
bare workspace-relative path that matches inside any package -- the collapse
`repoRelative` exists to stop, through the one door left open. And only a
`shared` path is reported as set aside: a `netNew` path was never eligible to
hold anything back, so calling it ignored coverage was noise on the very shape
that produces most keyed entries.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

— qwen3.8-max-preview via Qwen Code /review (v0.21.3)

Comment thread packages/cli/src/ui/auth/useProviderSetupFlow.ts Outdated
Comment thread packages/cli/src/serve/server/auth-provider-helpers.ts Outdated
Comment thread packages/core/src/providers/presets/kimi.ts
Comment thread packages/cli/src/ui/auth/AuthDialog.tsx
Comment thread packages/web-shell/client/components/messages/AuthMessage.tsx Outdated
Comment thread packages/cli/src/acp-integration/acpAgent.test.ts
wenshao added a commit that referenced this pull request Aug 2, 2026
…holds

Three rounds of self-review over the diff.

A finding a later round re-files as Critical was held again and gained a
second, identical explanation -- two paragraphs under one finding read as two
measurements, and the round ledger carrying a held finding forward is exactly
the path the structured field was added for. `heldByMeasurement` round-trips
now, so the state to decide this on is already there: lower it again, append
nothing.

Moving this section ahead of the verdict was necessary and not sufficient.
`compose-review` reads `comments.json` and `compose.json`, both hand-written,
so a severity lowered here still ships as `**[Critical]**` if the marker was
copied from the draft rather than the artifact. The skill now says to read
`severity` out of `findings.json` for every marker and body Critical, which is
what actually closes the path #8368 took.

And two of its own claims were wrong: "the blocks above already do" named one
block with the other still below it in Step 6B, and "Six test paths ... exist
under BOTH packages" is five -- a number carried over from a review comment
without being counted, in a change about not stating what nothing checked.
wenshao added a commit that referenced this pull request Aug 2, 2026
`test-delta` reruns the PR side's failed test commands on the merge base and
splits the failures into the PR's own (`netNew`) and pre-existing (`shared`).
Nothing then read that split back. A Critical asserting "this PR breaks test X"
could name a file the same run had just measured as failing without the PR, and
the two artifacts never met.

Measured on #8368: `AuthDialog.test.tsx` came back `shared` in two independent
runs, and the merge base e967cc9 fails the very same test --
`drives API key provider steps from endpoint options metadata`. A Critical
reading "height-based pagination breaks the pre-existing test" was carried
across four rounds into the composed review anyway. It only escaped posting
because the PR's head had moved. The path rule this misattribution used to come
through was closed inside `test-delta`; the round ledger is the other door.

`findings --test-delta` now holds such a Critical back to Suggestion and names
the finding and the file on stderr. Downgrade, never drop: the measurement
contradicts the severity, not necessarily the observation, since a test can be
red for two reasons at once. The finding keeps its own evidence, gains the
measurement that demoted it, and stays in front of a human who can restore it
by naming which test fails for a new reason and quoting both sides.

Both `review findings` invocations in the skill pass the flag. The second one
rebuilds the artifact from the same input, so leaving it off there would have
restored every Critical the first had just held back.
wenshao added a commit that referenced this pull request Aug 2, 2026
… them

The hold landed downstream of the thing it exists to correct. In the skill's
order `compose-review` ran first, so a Critical held back afterwards reached
only the Step 8 report: the verdict line, the drafted `**[Critical]**` marker
and the payload `submit` recounts were all fixed before the measurement was
consulted. That is the exact path the #8368 misattribution took into a composed
review, and this change had not closed it. The findings artifact is now written
before the verdict, and a hold arriving later is named as the comment-set
change it is.

`heldByMeasurement` did not survive `--input`. `validateFindings` builds from a
whitelist and never copied it, so the field a later round was supposed to read
lasted exactly one command and `counts.held` fell back to zero -- the same
invariant `outcomeNote` was added a few lines above to satisfy.

`locations[].file` left the haystack, for a sharper version of the reason
`suggestedFix` did. A finding ABOUT a test's content carries that test as its
location, and a PR touching an already-red test is precisely when such a
finding is written; demoting it uses the measurement against a claim the
measurement does not address.

The no-`entries` fallback is gone. It qualified nothing, so it put back the
bare workspace-relative path that matches inside any package -- the collapse
`repoRelative` exists to stop, through the one door left open. And only a
`shared` path is reported as set aside: a `netNew` path was never eligible to
hold anything back, so calling it ignored coverage was noise on the very shape
that produces most keyed entries.
wenshao added a commit that referenced this pull request Aug 2, 2026
…holds

Three rounds of self-review over the diff.

A finding a later round re-files as Critical was held again and gained a
second, identical explanation -- two paragraphs under one finding read as two
measurements, and the round ledger carrying a held finding forward is exactly
the path the structured field was added for. `heldByMeasurement` round-trips
now, so the state to decide this on is already there: lower it again, append
nothing.

Moving this section ahead of the verdict was necessary and not sufficient.
`compose-review` reads `comments.json` and `compose.json`, both hand-written,
so a severity lowered here still ships as `**[Critical]**` if the marker was
copied from the draft rather than the artifact. The skill now says to read
`severity` out of `findings.json` for every marker and body Critical, which is
what actually closes the path #8368 took.

And two of its own claims were wrong: "the blocks above already do" named one
block with the other still below it in Step 6B, and "Six test paths ... exist
under BOTH packages" is five -- a number carried over from a review comment
without being counted, in a change about not stating what nothing checked.
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully. The review pipeline failed before a review could be posted. A transient error is retried automatically; if you are seeing this, retry with @qwen-code /review. See workflow logs.

… dialog routes

The non-merge branches (minimax/zai/alibaba-standard shape: array baseUrl,
shared static env key, no mergeModelsByIdentity) stamped/dropped baseUrl-less
legacy entries without consulting legacyEnvKeyAttribution — the fail-closed
gate the merge branch enforces (R41-4). A connect at one endpoint deleted
(explicit selection) or re-homed (implicit reconnect) another endpoint's
untouchable entries, since non-merge install plans carry the UNSCOPED
ownsModel predicate.

- serve/ACP non-merge branches: carry entries with !namesSelectedEndpoint &&
  namesSiblingEndpoint through UNSTAMPED so they are written back
  byte-identical (R43-1/R43-2).
- serve non-merge branch: drop the requestedIds gate — the serve catalog
  exposes no existingConfig, so absence from an explicit modelIds selection
  is not deselection intent (R42-1 rationale); a defaults-only Web Shell/SDK
  reconnect no longer deletes same-endpoint stamped customs (R43-4). The ACP
  twin keeps its informed-deselection gate (its route seeds existingConfig).
- AuthDialog: extract one shared computePreservedModels helper for the two
  verbatim-twin flatMaps (getExistingProviderSetup + getProtocolSetups);
  seed baseUrl-less ids stamped only when namesSelectedEndpoint holds, emit
  them as migratedLegacyModelIds (plumbed through start()/protocol swap/
  buildCurrentInputs) so stored originals collapse instead of duplicating;
  shared/sibling keys unseeded everywhere, carried unstamped for non-merge
  providers; gate the models-field seed lists identically (R43-3).

Negative-controlled: all new regression tests fail on the pre-fix tree.
@DragonnZhang

Copy link
Copy Markdown
Collaborator Author

Round 43 — all 4 [Critical] findings verified against the code and confirmed real. All fixed in 9d74aafc29 (branch head 650769154b, merges upstream f877fb3525).

All four are the same defect family the merge branch already gates: the non-merge code paths (and the /auth dialog) stamp/drop baseUrl-less legacy entries without ever consulting legacyEnvKeyAttribution — the R41-4 fail-closed gate the merge branch enforces via adoptable = owned && (attributable || !namesSiblingEndpoint(model)). Verified impartially: provider-shape claims checked against every preset (minimax/zai/alibabaStandard are exactly the non-merge + array-baseUrl + shared static envKey set; deepseek is the single-endpoint non-merge control), and each witness reproduced by code-path analysis before writing the fixes.

Negative controls first: all new regression tests fail on the pre-fix tree exactly as the probes predict, then pass with the fixes.

  • R43-1 (ACP, acpAgent.ts non-merge branch) — real. The branch stamps every baseUrl-less entry with the selected endpoint before any endpoint check; attribution computed ~20 lines above is never consulted. For a shared static key, an explicit qwen/providers/connect omitting the id drops it from preserveModels, and since a non-merge install plan carries the unscoped ownsModel, prepend-and-remove-owned deletes the stored entry; with modelIds omitted it is preserved stamped — silently re-homed, flipped again on the next connect. Fix: entries with !namesSelectedEndpoint && namesSiblingEndpoint are carried through unstamped (return [model]) so they are written back byte-identical — omission alone would still delete them under the unscoped predicate. The ACP route keeps its informed-deselection requestedIds gate otherwise (this route seeds existingConfig, unlike serve).
  • R43-2 (serve, run-qwen-serve.ts non-merge branch) — real; serve twin of R43-1, separate copy, same fix applied there.
  • R43-3 (dialog, AuthDialog.tsx) — real. Both getExistingProviderSetup's and getProtocolSetups's preserve flatMaps stamped every baseUrl-less entry with the restored endpoint with no attribution gate and no migratedLegacyModelIds — and start() prefers preserveModelsByProtocol, so fixing only one flatMap would leave the re-homing unchanged, exactly as noted. Fix: extracted ONE shared computePreservedModels helper used by both flatMaps; baseUrl-less ids are seeded stamped only when namesSelectedEndpoint holds (with env key following the stamp, R39-6) and emitted as migratedLegacyModelIds (plumbed through start()/protocol-swap/buildCurrentInputs) so the stored original collapses instead of duplicating; shared/sibling keys are unseeded everywhere (also gated out of the models-field seed lists), and for non-merge providers carried through unstamped since their plans' unscoped ownsModel deletes anything that doesn't reach the plan.
  • R43-4 (serve non-merge deselection asymmetry) — real. The branch treated absence from an explicit modelIds as deselection, contradicting the R42-1 route-level rationale ~30 lines below in the same function ("the serve catalog exposes no existingConfig, so Web Shell and SDK selections are defaults-seeded and can never carry" saved ids). A stamped same-endpoint custom survived the implicit shape but was deleted by the explicit defaults-only shape this function was rewritten to handle. Fix: dropped the requestedIds gate in the non-merge branch (shouldPreserve = belongsToAnotherEndpoint || !defaultIds.has(preserved.id)), aligning it with the merge branch's merge-only semantics; seeded CLI/ACP/VS flows remain the authoritative deselection surfaces. The ACP twin intentionally keeps its gate (informed route).

Tests (all negative-controlled): serve e2e minimax explicit+implicit arms through buildInstallPlan+applyProviderInstallPlan (entry survives byte-identical, no stamped copy), serve deepseek defaults-only explicit reconnect preserves the stamped custom, ACP connect minimax both arms assert the unstamped carry, AuthDialog unit tests for both views (shared key unseeded/no migrate ids; sibling-attributable kept out of a foreign endpoint seed; attributable stamped + ids emitted), and two full dialog-chain flow tests (getExistingProviderSetup+getProtocolSetupsstart() → untouched submit()buildInstallPlan → apply): the Kimi shared-key entry survives alone and byte-identical, the deepseek attributable entry collapses to its stamped copy.

Verification: negative controls first — all 9 new tests fail on the pre-fix tree exactly as the probes predict, then pass with the fixes. Full regression: run-qwen-serve 280/280, acpAgent 472/472 (incl. a new minimax shape in the suite's mocked findProviderById, same pattern as the R42 kimi injection), AuthDialog 47/48 + the known 2-core TUI input-timing flake (should preserve the selected main entry when returning from each top-level flow — passes standalone; its fixture carries no modelProviders, so the changed code paths are inert in it; same flake class reproduced on clean HEAD in round 39), useProviderSetupFlow 33/33, ProviderSetupSteps/useAuth green, core providers 17 files / 208 passed, tsc --noEmit 0 errors, eslint 0, prettier clean.

One observed residual (not reported this round, recorded for the next review pass): the VS Code companion's AuthMessageHandler non-merge preserve branch (lines ~431-451) has the same missing-gate shape for baseUrl-less legacy entries; its merge branch fails closed by never restoring such entries. Left untouched here per the reported-surface scope of this round.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Unresolved, please confirm:

  • [Critical] 129 blocker threads from rounds 1-42 (2026-08-02 to 2026-08-22) could not be individually re-traced against this head within this round's time budget; the same-day round-43 re-check (2026-08-23) re-asserted none of them and all of their anc…

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not explored to full depth (tool budget reached): "agent invariant-a (packages/core/src/providers/provider-con…": none — no check was cut short.; chunk 10: did not execute the new tests — the review worktree has no node_modules (and no built dist/ ), and a full npm ci + workspace build + vitest run exceeded th…; chunk 35: none — no checks were cut short..

Not reviewed: reverse audit — stopped before round 3 by the review time budget.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 44, not a blocker) — recorded, not requested in this round:

  • packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.ts:24 — [review] desktop stripUserInfo normalizes https://@example.com differently from the CLI producer sanitizeProviderBaseUrl
  • packages/web-shell/client/components/messages/AuthMessage.tsx:205 — [review] startProvider keeps the previous provider's models when the descriptor baseUrl is an empty array
  • packages/cli/src/serve/run-qwen-serve.ts:6242 — [review] serve installAuthProvider existingModels wiring has no route-level test
  • packages/core/src/providers/__tests__/install.test.ts:1088 — [review] R38-3 test fixture key names no endpoint — sibling-attribution branch never exercised
  • packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.test.ts:1 (+2 locations) — [test] new desktop bun test suites run on no PR-gated CI job
  • packages/core/src/providers/__tests__/install.test.ts:713 — [probe] test leaks process.env[TOKEN_PLAN_ENV_KEY] (no try/finally cleanup)
  • packages/cli/src/acp-integration/acpAgent.test.ts:432 — [review] shared kimi mock has 2 endpoints — shared-MOONSHOT_API_KEY fail-closed branch unexercised
  • packages/cli/src/acp-integration/acpAgent.test.ts:13232 — [review] ACP sibling-exclusion test cannot reach the sibling-attribution branch (floating fixture key)
  • packages/cli/src/acp-integration/acpAgent.test.ts:13366 — [review] ACP R39-7 collapse test never asserts migratedLegacyModelIds
  • packages/desktop/packages/server-core/src/handlers/rpc/onboarding.ts:89 — [probe] hasExistingProviderConfig ignores modelIdsByBaseUrl — configured provider reported unconfigured
  • packages/cli/src/serve/run-qwen-serve.test.ts:503 — [probe] serve R39-7 test never asserts migratedLegacyModelIds; customProvider masks the claim
  • packages/core/src/providers/__tests__/install.test.ts:687 — [review] cross-provider merge tests never assert the other provider's entries survive
  • packages/core/src/providers/__tests__/install.test.ts:1190 — [probe] R39-2 test omits migratedLegacyModelIds — the !namesSiblingEndpoint guard is never load-bearing
  • packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.test.ts:479 — [review] resetTrimmedDefaultModelIds is tested but wired to no production caller
  • packages/web-shell/client/components/messages/auth-provider-state.test.ts:318 — [review] mimo fixture drops per-option envKeys and pins the wrong credential domain

Convergence: round 44 posted 4 inline comment(s), 4 of them reported for the first time; the previous round posted 4 (4 new). Findings keep coming back to the same files: packages/cli/src/serve/run-qwen-serve.ts (findings in round 43; 1 more now); packages/cli/src/ui/auth/AuthDialog.tsx (findings in round 43; 1 more now). The rate of new findings is not falling. A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. Batching the remaining fixes and verifying them before the next push keeps the loop from re-deriving the same set; this PR's reviews already resolve to a critical posting floor. (Observation only — nothing was withheld from this review because of this observation.)

[Critical] R44 re-check: existing blocker (comment 3827370555, packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts:436, anchored code unchanged since posting) STILL STANDS — deselecting a restored floating-key baseUrl-less legacy entry in the VS Code wizard is a silent no-op: ownsCustomEnvKeyShape rejects prefix-only keys, so the stored original is never claimed by the install plan and survives every deselection (this round's chunk-38 audit independently re-traced the mechanism at the reviewed head).

中文说明

仅完成部分审查,审查缺口已披露。

未决,请确认:共 1 条(原文未翻译,列表见上方英文部分)。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未探索到全部深度(达到工具调用预算):"agent invariant-a (packages/core/src/providers/provider-con…"none — no check was cut short.;chunk 10:did not execute the new tests — the review worktree has no node_modules (and no built dist/ ), and a full npm ci + workspace build + vitest run exceeded th…;chunk 35:none — no checks were cut short.

未审查:反向审计——评审时间预算不足,未能开始第 3 轮。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 44 轮,非阻断)——已记录,本轮不要求修改:共 15 条(原文未翻译,列表见上方英文部分)。

收敛情况:第 44 轮发布了 4 条行内评论,其中 4 条是首次提出;上一轮发布了 4 条(其中 4 条首次提出)。发现反复回到同一批文件:packages/cli/src/serve/run-qwen-serve.ts(第 43 轮已出过发现,本轮又有 1 条);packages/cli/src/ui/auth/AuthDialog.tsx(第 43 轮已出过发现,本轮又有 1 条)。新发现的产出速度没有下降。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。把剩余修复攒成一批、验证后再推送,可以避免循环反复推导同一组发现;本 PR 的评审已解析为 critical 发布下限。(仅为观察——本轮评审未因此扣留任何内容。)

[Critical] R44 re-check: existing blocker (comment 3827370555, packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts:436, anchored code unchanged since posting) STILL STANDS — deselecting a restored floating-key baseUrl-less legacy entry in the VS Code wizard is a silent no-op: ownsCustomEnvKeyShape rejects prefix-only keys, so the stored original is never claimed by the install plan and survives every deselection (this round's chunk-38 audit independently re-traced the mechanism at the reviewed head).

— qwen3.8-max via Qwen Code /review (v0.22.0)

Comment thread packages/core/src/providers/provider-config.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/cli/src/ui/auth/useProviderSetupFlow.ts Outdated
Comment thread packages/cli/src/ui/auth/AuthDialog.tsx
# Conflicts:
#	packages/cli/src/acp-integration/acpAgent.test.ts
…on round-tripped ids

R44-1: endpoint-match clause requires model.baseUrl !== undefined so a
free-form install with an empty resolved baseUrl cannot claim every
baseUrl-less legacy entry via '' === ''.

R44-3: id-collision clause additionally requires namesSelectedEndpoint, so
a floating key (names no endpoint) whose id collides with a migrated entry
is no longer claimed and deleted.

R44-2 + R44-4: add ProviderSetupInputs.roundTrippedLegacyModelIds. The
free-form env-key ownership clause treats omission as deselection only for
ids the caller exposed (or that the plan writes). Serve passes [] (catalog
exposes no existingConfig, absence is never deselection); the CLI dialog
passes the ids it surfaced, protecting an attributable entry it could not
restore/expose from silent deletion on submit.
@DragonnZhang

Copy link
Copy Markdown
Collaborator Author

Round 44 — all 4 [Critical] findings verified against the code and confirmed real. All fixed in f3c457057b. (Posted as one PR-level comment because inline replies remain blocked by the author's pending review 4851233521 / 550 drafts, which I do not touch.)

Each finding reproduces on 650769154b. Below is the per-item evidence, the fix, and the regression test. The branch is also merged up to current origin/main (13 commits; one acpAgent.test.ts conflict resolved by keeping both sides).


R44-1 — ownsModel endpoint-match clause degenerates at selectedEndpoint === '' (provider-config.ts). REAL.
normalizeBaseUrlForMatching(undefined) returns '', so a free-form install whose resolved baseUrl is '' made clause 1 evaluate '' === '' for every baseUrl-less entry and claim it, short-circuiting the attribution guard. Serve reaches this: parseAuthProviderBaseUrl(undefined) passes and buildProviderSetupInputs resolves to '' with no getDefaultBaseUrlForProtocol fallback (the ACP twin throws when still empty).
Fix: the endpoint-match clause now requires model.baseUrl !== undefined, so baseUrl-less entries are only owned through the attribution-guarded branch.
Test: an empty-baseUrl free-form install keeps the sibling / suffix-less / floating witness entries (all previously deleted).

R44-2 — R42-1 merge-only guarantee void for the free-form provider on serve (run-qwen-serve.ts). REAL.
For the free-form provider only, buildInstallPlan's env-key clause (freeFormProvider && ownsLegacyEnvKey) owns attributable baseUrl-less entries. An explicit-modelIds serve reconnect (the only shape Web Shell sends) dropped such an entry from preserveModels, and the env-key clause then deleted it.
Fix: added ProviderSetupInputs.roundTrippedLegacyModelIds; the env-key clause now treats omission as deselection only for ids the caller exposed (or that the plan writes). Serve passes [] — its catalog exposes no existingConfig, so absence is never deselection there. I used this plan-level signal rather than the suggested serve-side shouldPreserve rewrite because that rewrite would also preserve/stamp array-provider (KIMI) entries and regress the R42-1 byte-identical-survival tests; the round-trip gate scopes the change to the free-form env-key clause and leaves preserveModels untouched.
Test: an explicit serve reconnect at the entry's own endpoint keeps the attributable entry.

R44-3 — dialog migratedLegacyModelIds emission lets the id-collision claim delete a never-migrated floating entry (useProviderSetupFlow.ts / provider-config.ts). REAL.
The id-collision clause migratedLegacyModelIds.has(model.id), gated only by !namesSiblingEndpoint, claimed a baseUrl-less entry whose key names NO endpoint (floating prefix-only key) whenever its id collided with a migrated entry — namesSiblingEndpoint cannot protect a key that names no endpoint.
Fix: the id-collision clause additionally requires namesSelectedEndpoint(model). Callers only migrate attributable entries, so no real migration is under-claimed, but a floating entry is no longer reached by a colliding id.
Test: a floating entry sharing an id with a migrated attributable entry survives while the attributable twin still collapses.

R44-4 — dialog hides attributable baseUrl-less entries yet the plan claims them (AuthDialog.tsx). REAL.
When the first saved entry has no baseUrl, initialBaseUrl resolves to '', so the R43-3 attribution gate keeps the entry out of the seed; the env-key clause still owned it on submit (its stored key matched the typed endpoint), silently deleting a model the user was never shown. Deletion depended on array ordering in settings.
Fix: via the same roundTrippedLegacyModelIds mechanism, the dialog emits the ids it actually surfaced, so omission is deselection intent only for those. An attributable entry the dialog could not restore/expose is protected from the env-key claim; a surfaced-and-deselected entry is still removed (the bot's "suppress the claim for entries the dialog never exposed" option).
Tests: an unexposed attributable entry is protected; an exposed attributable entry that is deselected is still removed.


Verification (all under the build lock). With the fix applied, all four new R44 regression tests pass and the pre-existing suites stay green:

  • run-qwen-serve.test.ts: 281/281 (incl. R44-2 regression).
  • acpAgent.test.ts: 477/477.
  • core src/providers: 212/213 — the 1 failure is supportsImageGeneration from the merged upstream commit (code I did not touch).
  • CLI auth suites (AuthDialog / useProviderSetupFlow / useAuth / ProviderSetupSteps): 113/114 — the 1 failure is the documented 2-core TUI-timing flake (itWhenTuiInputReliable, skipped on CI), unrelated to this change (the dialog change only adds a data field to the submit inputs).

Negative control. Each regression test encodes the corresponding bot probe. On the unfixed code that probe deletes the entry — R44-1: survivor sib: 0 / sfx: 0 / flt: 0; R44-2: explicit arm survivors for my-custom: 0; R44-3: floating F deleted while the attributable twin collapses; R44-4: my-model survivor = undefined. Each test asserts the post-fix survival/collapse and passes with the fix applied (serve 281/281, core providers 212/213 including all four R44 tests).

Unrelated failures, noted for transparency (neither is in code this PR changed):

  • core providers 1/213 — supportsImageGeneration comes from the merged upstream commit (f1b1305a76, "dual-role image generation models"); it surfaced only under the heavy 17-file parallel run on this oversubscribed host.
  • CLI auth 1/114 — the documented 2-core TUI-timing flake in the itWhenTuiInputReliable navigation tests (skipped on CI, where CI=true); this round's dialog change only appends a data field to the submit inputs and touches no rendering/keyboard path.

The workflow grew from 29715 to 42519 bytes when QwenLM#9587 landed on main
without a baseline update (a latent main-side violation every PR merging
main now trips, as the check message itself directs). Record the new
size following the same remedy as QwenLM#9747/QwenLM#9682.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Unresolved, please confirm:

  • [Critical] Blocker threads from rounds 1-43 (~150 entries, all in this PR's provider-auth machinery files) could not be individually re-traced against this head within this round's time budget; the round-44 re-check carried them as cannot-tell under t…

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not explored to full depth (tool budget reached): chunk 43: running auth-provider-state.test.ts via vitest (no node_modules/built dist in the review worktree; install+build exceeds tool budget); "agent reverse-audit (round 1)": none — not emitting one per the brief (nothing was cut short); chunk 29: could not execute packages/core unit tests — the review worktree has no node_modules installed ( vitest unresolvable) and a full install+build exceeds the prac….

Not reviewed: reverse audit — stopped before round 3 by the review time budget.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 45, not a blocker) — recorded, not requested in this round:

  • packages/cli/src/ui/auth/AuthDialog.tsx:89 — [review] providerToItem description JSX duplicates renderItem's string wrapping
  • packages/cli/src/ui/auth/AuthDialog.tsx:262 — [probe] restoredModelIds can seed a duplicate id into the models field
  • packages/cli/src/ui/auth/AuthDialog.tsx:432 — [review] initialViewLevel prop set by no production caller (dead switch)
  • packages/cli/src/ui/auth/useProviderSetupFlow.ts:201 — [review] start() 13 positional params — two string[] slots transpose silently
  • packages/cli/src/ui/auth/useProviderSetupFlow.ts:251 — [review] custom-vs-trimmed-defaults split implemented three times (divergence risk)
  • packages/core/src/providers/__tests__/install.test.ts:713 — [review] test leaks process.env[TOKEN_PLAN_ENV_KEY] (no try/finally cleanup)
  • packages/core/src/providers/types.ts:130 — [review] envKeyNamesAnEndpoint docstring contradicts implementation
  • packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.ts:249 — [review] resetTrimmedDefaultModelIds dead export
  • packages/cli/src/serve/run-qwen-serve.ts:6250 — [review] serve install route preservation wiring has no route-level test
  • packages/cli/src/serve/run-qwen-serve.test.ts:503 — [probe] serve R39-7 collapse test never asserts migratedLegacyModelIds
  • packages/cli/src/acp-integration/acpAgent.test.ts:13564 — [probe] ACP R39-7 collapse test never asserts migratedLegacyModelIds
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:52 — [probe] METADATA_KEY rekey turned the non-default-baseUrl version-match test vacuous
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:1253 — [probe] negative-only assertions with no completion anchor
  • packages/cli/src/ui/auth/useProviderSetupFlow.test.ts:1447 — [probe] three full-chain tests leak process.env keys (no cleanup)
  • packages/core/src/providers/__tests__/presets/xiaomi-mimo.test.ts:118 — [probe] circular metadata-key assertion (function under test on both sides)
  • packages/web-shell/client/components/messages/auth-provider-state.test.ts:40 — [review] mimo fixture drops per-option envKeys — pins a shape the daemon never emits
  • packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.test.ts:1 — [test] new desktop bun:test suite runs on no PR-gated CI job
  • packages/desktop/packages/server-core/src/handlers/rpc/onboarding.test.ts:1 — [test] new desktop bun:test suite runs on no PR-gated CI job
  • scripts/tests/no-ak-integration-ci.test.js:214 — [test] root-level guard outside this review's scoped runs (CI-gated via test:scripts)

Convergence: round 45 posted 7 inline comment(s), 7 of them reported for the first time; the previous round posted 4 (4 new). The rate of new findings is not falling. Batching the remaining fixes and verifying them before the next push keeps the loop from re-deriving the same set; this PR's reviews already resolve to a critical posting floor. (Observation only — nothing was withheld from this review because of this observation.)

Mechanism health: this round did not close cleanly, so it withholds the incremental anchor — and the round it recovered had none either, so the next review re-reads the whole diff and will keep doing so until a round's marker carries an anchor again. (Stated, not acted on — this changes nothing about what the round posts.)

[Critical] R44-5 re-check: existing blocker (comment 3827370555, packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts:436) STILL STANDS — the round-44 fix commit f3c4570 does not touch AuthMessageHandler.ts; this round's end-to-end probes re-traced the VS Code wizard mechanism at HEAD: deselecting a restored floating-key baseUrl-less legacy entry remains a silent no-op (ownsCustomEnvKeyShape rejects prefix-only keys, so the stored original is never claimed by the install plan and survives every deselection), and seeded floating entries still duplicate permanently (see R45-5). 中文:第 44 轮修复提交未触及 AuthMessageHandler.ts;本轮端到端探针在 HEAD 重新追踪了 VS Code 向导机制:取消选择已恢复的浮动键无 baseUrl 遗留条目仍是静默无效操作,播种的浮动条目仍会永久重复(见 R45-5)。

中文说明

仅完成部分审查,审查缺口已披露。

未决,请确认:共 1 条(原文未翻译,列表见上方英文部分)。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未探索到全部深度(达到工具调用预算):chunk 43:running auth-provider-state.test.ts via vitest (no node_modules/built dist in the review worktree; install+build exceeds tool budget)"agent reverse-audit (round 1)"none — not emitting one per the brief (nothing was cut short);chunk 29:could not execute packages/core unit tests — the review worktree has no node_modules installed ( vitest unresolvable) and a full install+build exceeds the prac…

未审查:反向审计——评审时间预算不足,未能开始第 3 轮。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 45 轮,非阻断)——已记录,本轮不要求修改:共 19 条(原文未翻译,列表见上方英文部分)。

收敛情况:第 45 轮发布了 7 条行内评论,其中 7 条是首次提出;上一轮发布了 4 条(其中 4 条首次提出)。新发现的产出速度没有下降。把剩余修复攒成一批、验证后再推送,可以避免循环反复推导同一组发现;本 PR 的评审已解析为 critical 发布下限。(仅为观察——本轮评审未因此扣留任何内容。)

机制健康:本轮未能干净收尾,因而扣留了增量锚点,而它恢复到的那一轮也没有锚点,因此下一次评审将重读整个 diff——并会一直如此,直到某一轮的标记重新带上锚点。(仅陈述,不据此行动——这不改变本轮发布的任何内容。)

[Critical] R44-5 re-check: existing blocker (comment 3827370555, packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts:436) STILL STANDS — the round-44 fix commit f3c4570 does not touch AuthMessageHandler.ts; this round's end-to-end probes re-traced the VS Code wizard mechanism at HEAD: deselecting a restored floating-key baseUrl-less legacy entry remains a silent no-op (ownsCustomEnvKeyShape rejects prefix-only keys, so the stored original is never claimed by the install plan and survives every deselection), and seeded floating entries still duplicate permanently (see R45-5). 中文:第 44 轮修复提交未触及 AuthMessageHandler.ts;本轮端到端探针在 HEAD 重新追踪了 VS Code 向导机制:取消选择已恢复的浮动键无 baseUrl 遗留条目仍是静默无效操作,播种的浮动条目仍会永久重复(见 R45-5)。

— qwen3.8-max via Qwen Code /review (v0.22.0)

Comment thread packages/cli/src/acp-integration/acpAgent.ts Outdated
Comment thread packages/cli/src/acp-integration/acpAgent.ts
Comment thread packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts Outdated
Comment thread packages/cli/src/ui/hooks/useProviderUpdates.ts Outdated
Comment thread packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.ts Outdated
… floating ids

R45-1: readExistingProviderConfig seeded baseUrl-less legacy ids that fail
endpoint attribution into the top-level modelIds, the free-form
modelIdsByBaseUrl reduce, and the per-protocol views; the desktop client
submits the seed back as an explicit selection and adopts entries the install
plan can never claim back (a permanent duplicate). Gate every baseUrl-less
seed on namesSelectedEndpoint via a shared predicate.

R45-2: the merge branch adopted floating baseUrl-less entries (env key names
no endpoint) but the id-collision claim is gated on namesSelectedEndpoint,
which a floating key can never satisfy — the stamped copy persisted beside the
unclaimed original. Thread explicitly-adopted floating ids through a dedicated
ProviderSetupInputs.adoptedFloatingModelIds channel (ACP route + serve twin),
kept distinct from migratedLegacyModelIds so the R44-3 over-claim guard stays
intact.

R45-3: the free-form baseUrl Input onBlur early-returned without committing the
canonical form when it reconciled to the committed endpoint, so handleSubmit
submitted the raw trailing-slash/userinfo variant. Commit the canonical form.

R45-4: the VS Code non-merge branch stamped/deleted fail-closed shared-key
baseUrl-less entries (a non-merge plan carries the unscoped ownsModel). Carry
them through UNSTAMPED, mirroring ACP/serve/CLI.

R45-5: the VS Code restore path seeded+stamped floating entries it could never
claim. Gate the restored/seeded set on attribution and thread stamped
attributable ids via migratedLegacyModelIds so the install plan collapses the
stored original.

R45-6: the non-merge update flow conflated baseUrl-less legacy built-ins with
sibling-endpoint entries — a false "all models added" diff and a permanent
stamped duplicate per built-in. For single-endpoint (string-baseUrl) providers
count them as the selected endpoint's in both the preserve filter (template
replaces them) and the installed-id diff (not reported as additions).

R45-7: stripUserInfo truncated the authority at the first '/', diverging from
the producer sanitizeProviderBaseUrl when a basic-auth password contains '/',
'?', or '#'. Port the producer's guarded whole-string last-'@' fallback.

Regression tests added for each (core install, acpAgent, run-qwen-serve,
useProviderUpdates, VS Code AuthMessageHandler, desktop provider-state).
# Conflicts:
#	docs/users/configuration/auth.md
#	packages/cli/src/serve/core-runtime.ts
#	packages/core/src/providers/all-providers.ts
#	packages/core/src/telemetry/gen-ai-provider.test.ts
#	packages/core/src/telemetry/gen-ai-provider.ts
@DragonnZhang

Copy link
Copy Markdown
Collaborator Author

Round-45 response — all 7 [Critical] items verified line-by-line against the code at 7afbf33; all seven are genuine (several are regressions/edge-cases in our own round-36..44 machinery, as anticipated). All fixed in f9178ecc8b (branch head 16806044cc merges origin/main). Each fix has a regression test that fails on the pre-fix tree.

R45-1 — readExistingProviderConfig seeds unattributable baseUrl-less ids (all 3 surfaces). Confirmed. The endpoint-scoped (array-merge) path has the namesSelectedEndpoint gate, but the non-scoped path seeded every baseUrl === undefined model unconditionally into the top-level modelIds, the free-form modelIdsByBaseUrl reduce, and the per-protocol byEndpoint loop. The desktop client submits that seed back verbatim as an explicit selection, the connect handler adopts+stamps it, but buildInstallPlan can never claim a floating key → permanent duplicate. Fix: compute legacyEnvKeyAttribution(config, protocol, baseUrl) once (and per protoBaseUrl in the protocol loop) and gate every baseUrl-less seed on namesSelectedEndpoint via a shared seedableRestoredLegacy predicate — mirroring the CLI dialog gate. Attributable ids are still seeded so an echoed seed keeps its R42-1 deselection meaning. Tests: acpAgent.test.ts "does not seed floating baseUrl-less legacy ids on a free-form provider (R45-1)".

R45-2 — merge branch adopts floating baseUrl-less entries but can never claim them. Confirmed (ACP and its serve twin). adoptable = owned && (attributable || !namesSiblingEndpoint) lets a floating key through, and the id was pushed to migratedLegacyModelIds, but the id-collision claim is gated on migratedLegacyModelIds.has(id) && namesSelectedEndpoint(model) — which a floating key can never satisfy — so the stamped copy was written beside the unclaimed original (verified: 2 entries pre-fix). Fix: thread explicitly-adopted floating ids through a new, dedicated adoptedFloatingModelIds channel on ProviderSetupInputs; buildInstallPlan claims them in the baseUrl-less clause, kept distinct from migratedLegacyModelIds so the R44-3 over-claim guard (a floating entry whose id merely collides with a migrated attributable entry) stays intact. Applied to both the ACP route and the serve twin. Tests: core install.test.ts (claim + the guard) and acpAgent.test.ts "(R45-2)".

R45-3 — free-form baseUrl Input onBlur early-returns without setBaseUrl. Confirmed. When canonicalBaseUrl reconciles to the committed endpoint the handler returned without committing the canonical text, so handleSubmit (which submits the raw baseUrl) persisted the trailing-slash / userinfo variant. Fix: exactly the suggested change — still setBaseUrl(nextBaseUrl) when the canonical form differs from the field state before returning.

R45-4 — VS Code non-merge branch stamps/deletes fail-closed shared-key entries. Confirmed. This is the AuthMessageHandler gap the round-43/44 notes already flagged as a known residual; minimax/zai/alibaba-standard (non-merge, array baseUrl, one shared static key) fail attribution closed, yet isSelectedEndpointModel returned true purely on baseUrl === undefined, so the accept path re-homed the entry and the deselect path deleted it (unscoped non-merge ownsModel). Fix: apply legacyEnvKeyAttribution in the models step and carry baseUrl === undefined && !namesSelectedEndpoint && namesSiblingEndpoint entries through UNSTAMPED (return [model]) before the default/selection checks — mirroring ACP/serve/CLI. Test: AuthMessageHandler.test.ts "(R45-4)".

R45-5 — VS Code restore path seeds+stamps floating entries it can never claim. Confirmed (same root as the round-44 blocker on this file). For merge free-form, endpointScoped is false so every baseUrl-less entry passed the filter; the R34-4 fixture is precisely such a floating entry. It was stamped into preserveModels but the stored original is claimable only via ownsLegacyEnvKey or migratedLegacyModelIds+attribution — a floating key satisfies none → both entries persisted. Fix: gate the restored/seeded set on namesSelectedEndpoint (floating entries are never seeded or stamped), and for attributable entries now stamped, pass their ids as migratedLegacyModelIds so the install plan collapses the stored original. The R34-4 test is updated accordingly (its fixture was a floating key; it now uses an attributable key and asserts the collapse), plus a new floating test. Tests: AuthMessageHandler.test.ts "(R34-4 × R45-5)" and "(R45-5)".

R45-6 — non-merge update flow conflates baseUrl-less legacy entries with sibling entries. Confirmed. modelsAtBaseUrl can't see a baseUrl-less entry (normalizeBaseUrlForMatching(undefined) = ''), so the diff reported installed built-ins as additions, while the preserve filter kept them → a stamped template copy written beside each baseUrl-less built-in, permanently. Base replaced them cleanly. Fix: for non-merge single-endpoint (string baseUrl) providers, count an owned baseUrl-less entry as belonging to the selected endpoint in both the preserve filter (so the template replaces it) and getInstalledOwnedModelIds (so the diff sees it as installed). Array-baseUrl providers keep the safe preserve behavior (a baseUrl-less entry can't be attributed to one region). Test: useProviderUpdates.test.ts "(R45-6)".

R45-7 — stripUserInfo truncates the authority at the first /. Confirmed (reproduced side-by-side): a basic-auth password containing / (or ?/#) delimits the authority before the @, so the consumer returned the URL with userinfo intact while the producer's sanitizeProviderBaseUrl strips it via the whole-string last-@ fallback when new URL() throws. Fix: ported the producer's algorithm verbatim (scheme/authority parse → new URL attempt → guarded whole-string last-@ fallback via findUnescapedUserInfoFallbackAt). Test: provider-state.test.ts "(R45-7)".

Verification (all under the shared build lock, re-run after merging origin/main): core install 53, acpAgent 474, run-qwen-serve 282, useProviderUpdates 54, VS Code AuthMessageHandler 16, desktop provider-state 38 — all green; the new regression tests fail on the pre-fix tree (negative controls).

Merge note: origin/main (27 commits) was merged into the branch. This brought moonshotProvider (#9814) which overlaps this PR's Kimi API endpoints on MOONSHOT_API_KEY; the telemetry/provider-registry conflicts were resolved by deferring to main's dedicated moonshot attribution (api.moonshot.ai/cnmoonshot, kimi.com coding → kimi) and inserting moonshotProvider in label-sorted registry position. A pre-existing upstream-merge type error in serve/workspace-providers-status.test.ts (configOptions) is untouched by this PR and left as-is.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not explored to full depth (tool budget reached): chunk 11: executing AuthDialog.test.tsx to observe the failure (worktree has no node_modules ; full npm ci + build exceeds the tool budget); chunk 25: executing install.test.ts under vitest — the review worktree has no node_modules , and npm ci + monorepo build exceeded this chunk's tool budget; all expec…; "agent invariant-b (packages/core/src/providers/provider-con…": none — no check was cut short..

Not reviewed: reverse audit — stopped before round 2 by the review time budget.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 46, not a blocker) — recorded, not requested in this round:

  • packages/cli/src/ui/auth/useProviderSetupFlow.ts:477 — [probe] selectProtocol clears apiKeyError/modelIdsError but not baseUrlError — stale validation error after a protocol switch
  • packages/cli/src/ui/auth/useProviderSetupFlow.ts:601 — [probe] submitBaseUrl swaps the visible API key without clearing apiKeyError — stale empty-key error under a restored key
  • .github/workflows/ci.yml:586 — [review] no-AK gate blanks MIMO_API_KEY but omits MIMO_TOKEN_PLAN_API_KEY (+ scripts/tests/no-ak-integration-ci.test.js pinned list)
  • packages/cli/src/ui/auth/AuthDialog.tsx:582 — [review] CUSTOM_PROVIDER case duplicates handleProviderSelect's body verbatim (13-positional start call) — drift risk
  • packages/desktop/apps/electron/src/renderer/components/apisetup/ProviderConnectForm.tsx:262 — [review] seed-application block triplicated across selectProvider and both handleProtocolChange branches
  • packages/desktop/apps/electron/src/renderer/components/apisetup/ProviderConnectForm.tsx:552 — [review] no component-level test for the new glue (blur canonicalization commit, protocol-flip re-seed, reconciliation)
  • docs/users/configuration/auth.md:6 — [review] Third-party Providers list omits 'Kimi (Moonshot AI) API Key' while it remains selectable — coupled to the R46-1 resolution
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:891 — [review] no-inference tests assert on setValue instead of the batched setValues writer — the guard can never fail (mutation-probed)
中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未探索到全部深度(达到工具调用预算):chunk 11:executing AuthDialog.test.tsx to observe the failure (worktree has no node_modules ; full npm ci + build exceeds the tool budget);chunk 25:executing install.test.ts under vitest — the review worktree has no node_modules , and npm ci + monorepo build exceeded this chunk's tool budget; all expec…"agent invariant-b (packages/core/src/providers/provider-con…"none — no check was cut short.

未审查:反向审计——评审时间预算不足,未能开始第 2 轮。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 46 轮,非阻断)——已记录,本轮不要求修改:共 8 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.22.0)

Comment thread packages/core/src/providers/all-providers.ts
Comment thread packages/cli/src/ui/auth/AuthDialog.test.tsx
…stry discovery

R46-1: kimiProvider derives MOONSHOT_API_KEY for its regional API endpoints
(api.moonshot.{ai,cn}/v1) while the upstream moonshotProvider declares the
same key statically for the same URLs, and findProviderByCredentials was a
plain first-match find over ALL_PROVIDERS — kimi registered first, so the
lookup that resolved to moonshot at the merge base resolved to kimi and
moonshot.test.ts failed ('expected kimi to be moonshot'). Make credential
discovery deterministic instead of order-dependent: a preset declaring the
env key statically is the canonical owner of that credential space and beats
presets that only derive the same key via a function envKey. This keeps the
round-45 adjudication (MOONSHOT_API_KEY attribution belongs to the upstream
moonshot provider, as in telemetry) while kimi keeps its regional API
endpoints selectable and uniquely owns the KIMI_CODE_API_KEY Coding Plan
space. Registry label order stays untouched. Tests: pin the collision
outcome in all-providers.test.ts and flip kimi.test.ts's discovery
assertions to the adjudicated owner.

R46-2: the AuthDialog provider-walk test omitted 'Kimi (Moonshot AI) API
Key', which the alphabetical THIRD_PARTY_PROVIDERS sort places between
'Kimi' and 'MiniMax API Key' — the walk landed on the moonshot label and
timed out waiting for MiniMax (gated by itWhenTuiInputReliable, so it only
failed outside CI). Insert the missing label.
@DragonnZhang

Copy link
Copy Markdown
Collaborator Author

Round-46 response — both Critical threads verified genuine and fixed in 6432e8e.

R46-1 (all-providers.ts:69) — credential-space collision: confirmed. Reproduced at prior HEAD: findProviderByCredentials was a plain first-match find over ALL_PROVIDERS; kimiProvider registers ahead of moonshotProvider while deriving the same MOONSHOT_API_KEY for the same api.moonshot.{ai,cn}/v1 URLs, so the lookup resolved to kimi and upstream moonshot.test.ts failed with expected 'kimi' to be 'moonshot' (core provider suite: 1/222 failing). Our own kimi.test.ts simultaneously claimed the same lookup for kimi — the two suites contradicted each other. This also conflicted with the round-45 adjudication that already attributes MOONSHOT_API_KEY to the upstream moonshot provider in telemetry.

Fix: credential discovery is now deterministic instead of order-dependent — a preset declaring the env key statically is the canonical owner of that credential space and beats presets that only derive the same key via a function envKey. Moonshot wins the shared space (matching the telemetry attribution); Kimi keeps its regional API endpoints selectable and uniquely owns the KIMI_CODE_API_KEY Coding Plan space. Registry/label order stays untouched, so the label-sort invariant still holds. Pinned by a new collision test in all-providers.test.ts; kimi.test.ts assertions flipped to the adjudicated owner.

R46-2 (AuthDialog.test.tsx:1846) — walk-list omission: confirmed. Reproduced at prior HEAD: after 'Kimi', the frame shows › Kimi (Moonshot AI) API Key selected and the walk times out waiting for 'MiniMax API Key' (gated by itWhenTuiInputReliable, so it only failed outside CI). The missing label is inserted at its alphabetical position.

Verification at new head 6432e8e: core provider suite 223/223 (was 221/222, plus one new regression test); AuthDialog.test.tsx 48/48; adjacent consumers (systemInfoFields, AppHeader, useProviderUpdates, useProviderSetupFlow, ProviderSetupSteps, doctorChecks, auth-provider-helpers) 125/125; run-qwen-serve.test.ts 282/282; core tsc --build clean (typechecks the edited test files). Note: tsc --noEmit for packages/cli OOMs in this 2-core/3.5 GB review environment (pre-existing infra limit, not code); the only cli-side change is a single string literal in a test file that runs green, and CI typecheck remains authoritative.

The merge of origin/main lost the typecheck:integration script and its
reference in the typecheck script, breaking the CI typecheck step
(Missing script: typecheck:integration). Restore both from main.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

— qwen3.8-max via Qwen Code /review (v0.22.0)

# Conflicts:
#	packages/desktop/apps/electron/src/renderer/components/apisetup/ProviderConnectForm.tsx
#	packages/desktop/packages/server-core/src/handlers/rpc/onboarding.ts
#	packages/desktop/packages/shared/src/protocol/dto.ts
@DragonnZhang
DragonnZhang requested a review from qqqys as a code owner August 25, 2026 08:21

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not reviewed: reverse audit — stopped before round 3 by the review time budget.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 48, not a blocker) — recorded, not requested in this round:

  • .github/workflows/ci.yml:611 — [review] The new Xiaomi MiMo preset reads a second env key,…
  • packages/cli/src/acp-integration/acpAgent.test.ts:13709 — [review] The R39-7 twin-collapse test asserts only preserveModels…
  • packages/cli/src/ui/auth/AuthDialog.tsx:151 — [probe] getMaxItemsToShow always reserves SCROLL_AFFORDANCE_ROWS…
  • packages/cli/src/ui/auth/AuthDialog.tsx:314 — [probe] restoredModelIds is never deduplicated, so in the…
  • packages/cli/src/ui/auth/AuthDialog.tsx:433 — [review] The new initialViewLevel prop is declared and read…
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:547 — [review] The only test pinning a merge-provider update with a…
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:895 — [review] The three 'no inferred kimi-- metadata persisted' guards…
  • packages/cli/src/ui/hooks/useProviderUpdates.ts:239 — [probe] persistEndpointMetadataMigration swallows every setValues…
  • packages/cli/src/ui/hooks/useProviderUpdates.ts:261 — [probe] The R45-6 fix that stops baseUrl-less legacy built-ins…
  • packages/core/src/providers/__tests__/install.test.ts:722 — [probe] The token-plan key-rotation test ('keeps an id-only…
  • packages/desktop/apps/electron/src/renderer/components/apisetup/provider-state.ts:294 — [review] resetTrimmedDefaultModelIds is an exported helper with no…
  • packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.test.ts:449 — [probe] The R45-5/R45-4 regression tests (also :490-491) assert…
中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未审查:反向审计——评审时间预算不足,未能开始第 3 轮。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 48 轮,非阻断)——已记录,本轮不要求修改:共 12 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.22.0)

Comment thread packages/cli/src/ui/auth/AuthDialog.tsx Outdated
Comment thread packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts Outdated
Comment thread packages/desktop/packages/server-core/src/handlers/rpc/onboarding.test.ts Outdated
Comment thread packages/cli/src/ui/hooks/useProviderUpdates.ts Outdated
Comment thread packages/cli/src/acp-integration/acpAgent.ts Outdated
Comment thread packages/cli/src/acp-integration/acpAgent.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts Outdated
Comment thread packages/cli/src/ui/auth/AuthDialog.tsx
…-out

main removed packages/desktop (QwenLM#9085, OpenWork fork); this branch's
provider-state module and desktop onboarding test no longer have their
surrounding implementation. The Kimi/Xiaomi auth work for live surfaces
remains in cli and vscode-ide-companion.
Round-46 findings (all negative-controlled):

R46-1 (AuthDialog): getProtocolSetups computed attribution and
computePreservedModels only for truthy protoBaseUrl, while the flat view
gated on initialBaseUrl === undefined — a free-form bucket whose first
saved model has no baseUrl resolves to '' and lost its preserveModels on
any protocol switch-and-back. Both are now computed unconditionally.

R46-2 (AuthMessageHandler): isSelectedEndpointModel required
model.baseUrl !== undefined for endpoint-scoped merge providers, so every
baseUrl-less legacy entry was dropped before attribution — dead wiring for
the Kimi/Xiaomi presets. Attributable entries are admitted, stamped, and
recorded in migratedLegacyModelIds; kimi test updated (+ regression).

R46-3 (useProviderUpdates): for string-baseUrl (no-sibling) providers the
preservedModels filter kept built-ins stamped at a stale URL as "sibling"
entries, duplicating every built-in when a preset URL changes. Preservation
is now limited to custom ids for single-endpoint providers.

R46-4 (acpAgent): list-time seeding skipped ''-baseUrl per-protocol buckets
(attribution now unconditional), and connect claimed every
attributable-but-absent entry as an informed deselection while never
passing roundTrippedLegacyModelIds. Connect now threads the ids the
list-time seed actually exposed (collectSeededModelIds) and scopes the
R41-3 pure-absence claim to that set plus generated-default supersession.

R46-5 (acpAgent + serve): the non-merge branches never applied the R39-7
stamped-twin collapse — a same-id legacy+stamped pair persisted as two
identical (id, baseUrl) entries. Both branches now consult
stampedIdsAtSelectedEndpoint (after the fail-closed carry).

R46-6 (serve + acpAgent): the R39-7 collapse pushed floating originals
into adoptedFloatingModelIds even on implicit reconnects — id collision
alone decided deletion (R39-3). Adoption is now gated on
hasExplicitModelIds && requested; implicit reconnects leave the entry
unclaimed.

R46-7 (AuthDialog): array-baseUrl entries stamped at a URL matching no
preset option diverged from the submission endpoint — submitting wrote a
stamped copy at the first option beside the unclaimed stale original.
Snapping the restored endpoint broke the main-pinned prefill contract
(token-plan test), so the restore keeps the raw URL and the duplicate is
closed at submit: buildCurrentInputs re-stamps stale entries at the
submission endpoint and emits their ids in migratedLegacyModelIds, and
buildInstallPlan gains an R40-2-disciplined stale-stamped claim clause.

R46-8 (AuthMessageHandler + dialog): the VS Code surface (and the CLI
dialog) never populated adoptedFloatingModelIds — a floating entry whose id
the user explicitly typed was regenerated stamped while the stored original
could never be claimed. Both surfaces now adopt such entries through the
dedicated channel.

Tests added across AuthDialog/useProviderSetupFlow/useProviderUpdates/
acpAgent/run-qwen-serve/AuthMessageHandler suites.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not explored to full depth (tool budget reached): chunk 6: executing the describe block to confirm it goes green — the review worktree has no node_modules or built workspace dist/ outputs, and a full npm ci + buil…; chunk 26: running packages/core vitest on install.test.ts (worktree has no node_modules/dist; full install+build exceeded the tool budget); chunk 25: running install.test.ts under vitest to confirm the traced expectations execute green (no built dist/ in the review worktree).; chunk 17: executing useProviderSetupFlow.test.ts under vitest — the review worktree has no node_modules (and neither does the parent checkout), so npm ci plus the w….

Not reviewed: reverse audit — stopped before round 3 by the review time budget.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 49, not a blocker) — recorded, not requested in this round:

  • .github/workflows/ci.yml:688 — [review] MIMO_TOKEN_PLAN_API_KEY missing from the no-AK gate blanking list and its pin test
  • packages/core/src/providers/__tests__/install.test.ts:713 — [review] Token-plan reinstall test leaks BAILIAN_TOKEN_PLAN_API_KEY into process.env for the rest of the file
  • packages/core/src/providers/__tests__/install.test.ts:1449 — [review] R44-3 test's toContainEqual pair cannot detect the unclaimed original surviving
  • packages/cli/src/ui/auth/AuthDialog.tsx:687 — [review] Saved-state wiring block duplicated verbatim across handleProviderSelect and handleMainSelect
  • packages/cli/src/ui/auth/useProviderSetupFlow.ts:510 — [review] selectProtocol clears apiKeyError and modelIdsError but not baseUrlError
  • docs/users/configuration/auth.md:6 — [review] Provider list omits the legacy Moonshot preset; /auth now renders two adjacent Kimi entries
  • packages/vscode-ide-companion/src/services/settingsWriter.ts:420 — [review] writeModelProvidersConfig deletes only bare plan metadata keys, leaving endpoint-suffixed keys (phantom update prompts)
  • scripts/tests/no-ak-integration-ci.test.js:220 — [test] The modified no-AK integration test is unreachable by any workspace test command and its CI gate is conditional
  • packages/cli/src/serve/run-qwen-serve.ts:1971 — [review] Fail-closed baseUrl-less DEFAULT-id entries carried unstamped while stamped twins regenerated (permanent duplicate pair)
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:1007 — [review] Three negative inference tests assert setValue (singular) but the guarded path persists via setValues (batch)
  • packages/core/src/providers/__tests__/presets/xiaomi-mimo.test.ts:128 — [review] MiMo metadata-key assertions are circular — computed by the function under test
  • packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.test.ts:456 — [review] R45-5/R45-4 tests assert the typed input, not the seeded prefill — the seeding gate is untested
  • packages/web-shell/client/components/messages/AuthMessage.tsx:205 — [review] startProvider: a provider with baseUrl: [] slips through both model seeders — stale models field
  • packages/cli/src/acp-integration/acpAgent.test.ts:13895 — [review] R39-7 fixture has only two kimi endpoints — the fail-closed MOONSHOT survival it claims to pin never exercises
  • packages/cli/src/serve/run-qwen-serve.test.ts:1009 — [review] R44-2 test asserts survival by id alone — survival-with-mutation not caught
  • packages/cli/src/serve/run-qwen-serve.ts:7211 — [review] Twin-collapse reads ownsModel-filtered models — a name-prefix-stripped stamped twin is invisible (permanent duplicate)
  • packages/cli/src/ui/auth/AuthDialog.test.tsx:590 — [review] R43-3 fail-closed tests never assert floatingLegacyModels stays empty — adoption-channel exclusion untested

Convergence: round 49 posted 6 inline comment(s), 6 of them reported for the first time; the previous round posted 10 (10 new). Findings keep coming back to the same files: packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts (findings in round 48; 2 more now); packages/cli/src/acp-integration/acpAgent.ts (findings in round 48; 1 more now). A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. (Observation only — nothing was withheld from this review because of this observation.)

中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未探索到全部深度(达到工具调用预算):chunk 6:executing the describe block to confirm it goes green — the review worktree has no node_modules or built workspace dist/ outputs, and a full npm ci + buil…;chunk 26:running packages/core vitest on install.test.ts (worktree has no node_modules/dist; full install+build exceeded the tool budget);chunk 25:running install.test.ts under vitest to confirm the traced expectations execute green (no built dist/ in the review worktree).;chunk 17:executing useProviderSetupFlow.test.ts under vitest — the review worktree has no node_modules (and neither does the parent checkout), so npm ci plus the w…

未审查:反向审计——评审时间预算不足,未能开始第 3 轮。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 49 轮,非阻断)——已记录,本轮不要求修改:共 17 条(原文未翻译,列表见上方英文部分)。

收敛情况:第 49 轮发布了 6 条行内评论,其中 6 条是首次提出;上一轮发布了 10 条(其中 10 条首次提出)。发现反复回到同一批文件:packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts(第 48 轮已出过发现,本轮又有 2 条);packages/cli/src/acp-integration/acpAgent.ts(第 48 轮已出过发现,本轮又有 1 条)。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。(仅为观察——本轮评审未因此扣留任何内容。)

— qwen3.8-max via Qwen Code /review (v0.22.0)

Comment thread packages/cli/src/acp-integration/acpAgent.ts
Comment thread packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.ts Outdated
Comment thread packages/cli/src/ui/auth/useProviderSetupFlow.ts
Comment thread packages/cli/src/ui/auth/useProviderSetupFlow.ts
Comment thread packages/cli/src/ui/auth/useProviderSetupFlow.ts
Close six interlocking defects in the stale-stamped / baseUrl-less
legacy-model claim machinery surfaced by round-2 review.

- VS Code: record the migratedLegacyModelIds claim for EVERY attributable
  baseUrl-less entry admitted to the seed (selected or not), ahead of the
  twin dedup, so a deselection is owned instead of no-oping forever.
- VS Code: adopt an explicitly typed stale-stamped id (re-stamp at the
  submission endpoint + claim) so the pair collapses.
- ACP + serve: add the stale-stamped claim branch mirroring the CLI — a
  requested id re-stamps and is claimed; an exposed-but-omitted id is an
  informed deselection; a never-exposed entry is never claimed.
- CLI dialog: gate the stale-stamped branch on which ids the views actually
  prefilled (surfacedStaleModelIds); a never-surfaced stale entry fails
  closed (left out of the plan) instead of being claimed and deleted.
- CLI dialog: when the restored endpoint diverges from the resolved one
  (first saved model is a stale stamp), seed the models field from the
  resolved endpoint's own bucket so genuinely-saved defaults render checked.
- CLI dialog: carry a non-merge ARRAY-baseUrl provider's restored-endpoint
  DEFAULT entries so switching endpoint before submit does not delete them.

Adds one regression test per finding (R46-1..R46-6) and keeps the prior
round's negative controls green.
…omi-auth

# Conflicts:
#	packages/cli/src/ui/auth/AuthDialog.test.tsx
#	packages/cli/src/ui/auth/ProviderSetupSteps.test.tsx
#	packages/cli/src/ui/auth/ProviderSetupSteps.tsx

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not explored to full depth (tool budget reached): chunk 28: run kimi.test.ts under vitest — the review worktree has no node_modules / dist , and npm ci + npm run build exceeds the tool budget; every assertion was ….

Not reviewed: reverse audit — stopped before round 3 by the review time budget.

Not reviewed: the diff sections covering packages/cli/src/ui/auth/ProviderSetupSteps.test.tsx, packages/cli/src/ui/auth/ProviderSetupSteps.tsx, packages/core/src/providers/tests/presets/xiaomi-mimo.test.ts, packages/core/src/providers/tests/provider-config.test.ts, "agent verify (round 2)" — pointed at diff lines it never opened: it made tool calls, but none of them read the diff.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 50, not a blocker) — recorded, not requested in this round:

  • .github/workflows/ci.yml:626 — [review] MIMO_TOKEN_PLAN_API_KEY missing from the no-AK gate blanking list and its pin test
  • packages/cli/src/acp-integration/acpAgent.test.ts:13900 — [probe] R39-7 fixture has only two kimi endpoints — the fail-closed MOONSHOT survival it claims to pin never exercises
  • packages/cli/src/serve/run-qwen-serve.ts:1906 — [review] hasExplicitModelIds treats [] as explicit while normalizeInstallModelIds treats [] as implicit
  • packages/cli/src/serve/run-qwen-serve.ts:77 — [review] module-scope static import of legacyEnvKeyAttribution bypasses the loadCoreRuntime fast-path boundary
  • packages/core/src/providers/__tests__/install.test.ts:713 — [review] token-plan reinstall test leaks BAILIAN_TOKEN_PLAN_API_KEY into process.env for the rest of the file
  • packages/core/src/providers/__tests__/install.test.ts:1090 — [review] R38-3 fixture uses a prefix-only floating key, not the old-shape legacy key it claims
  • packages/cli/src/acp-integration/acpAgent.test.ts:13797 — [probe] R45-5 fixture/mock cannot exercise the free-form sibling-guard arm
  • packages/cli/src/acp-integration/acpAgent.ts:1828 — [probe] seed escape hatch over-seeds stamped models when the first saved model has no baseUrl
  • packages/cli/src/ui/auth/AuthDialog.test.tsx:244 — [review] doubled fixed 50ms sleeps on both sides of every keystroke add dead wall-clock per local run
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:52 — [review] METADATA_KEY rename to the China-endpoint key vacuates the global-endpoint versions-match test
  • packages/cli/src/ui/hooks/useProviderUpdates.test.ts:976 — [probe] three negative inference tests assert setValue (singular) but the guarded path persists via setValues (batch)
  • packages/core/src/providers/__tests__/install.test.ts:1449 — [probe] R44-3 migrated-claim clause (a) is shadowed by the free-form clause (b)
  • packages/core/src/providers/__tests__/provider-config.test.ts:1250 — [review] sibling-protection assertion missing for the international moonshot endpoint despite the plural comment
  • packages/core/src/providers/provider-config.ts:473 — [probe] preserved entries with no generated twin are appended with their stale envKey on the serve path
  • packages/vscode-ide-companion/src/webview/handlers/AuthMessageHandler.test.ts:560 — [probe] R45-4 asserts the typed input, not the seeded prefill — the admission gate is untested
  • packages/cli/src/acp-integration/acpAgent.test.ts:580 — [review] mock resolvers bypass the trailing-slash normalization their real counterparts apply
  • packages/cli/src/ui/auth/useProviderSetupFlow.test.ts:194 — [probe] seven tests leak fixture API keys into process.env with no cleanup
  • packages/cli/src/ui/hooks/useProviderUpdates.ts:258 — [probe] merge providers' baseUrl-less legacy built-ins are reported as added and duplicated on update

Convergence: round 50 posted 4 inline comment(s), 3 of them reported for the first time; the previous round posted 6 (6 new). Findings keep coming back to the same files: packages/cli/src/acp-integration/acpAgent.ts (findings in round 49; 1 more now); packages/cli/src/ui/auth/useProviderSetupFlow.ts (findings in round 49; 1 more now). A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. (Observation only — nothing was withheld from this review because of this observation.)

中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未探索到全部深度(达到工具调用预算):chunk 28:run kimi.test.ts under vitest — the review worktree has no node_modules / dist , and npm ci + npm run build exceeds the tool budget; every assertion was …

未审查:反向审计——评审时间预算不足,未能开始第 3 轮。

未审查:涉及 packages/cli/src/ui/auth/ProviderSetupSteps.test.tsx、packages/cli/src/ui/auth/ProviderSetupSteps.tsx、packages/core/src/providers/tests/presets/xiaomi-mimo.test.ts、packages/core/src/providers/tests/provider-config.test.ts 的 diff 片段、"agent verify (round 2)"——启动 prompt 为它指定了 diff 中的行,但它从未打开:有工具调用,却没有一次读取 diff。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 50 轮,非阻断)——已记录,本轮不要求修改:共 18 条(原文未翻译,列表见上方英文部分)。

收敛情况:第 50 轮发布了 4 条行内评论,其中 3 条是首次提出;上一轮发布了 6 条(其中 6 条首次提出)。发现反复回到同一批文件:packages/cli/src/acp-integration/acpAgent.ts(第 49 轮已出过发现,本轮又有 1 条);packages/cli/src/ui/auth/useProviderSetupFlow.ts(第 49 轮已出过发现,本轮又有 1 条)。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。(仅为观察——本轮评审未因此扣留任何内容。)

— qwen3.8-max via Qwen Code /review (v0.22.0)

Comment thread packages/cli/src/ui/auth/useProviderSetupFlow.ts
Comment thread packages/cli/src/acp-integration/acpAgent.ts
Comment thread packages/cli/src/ui/auth/AuthDialog.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autofix/needs-human The autofix loop stopped on this PR — a human must re-arm, split, merge, or close it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants